@collabdt/core 0.0.55 → 0.0.56
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 +3 -3
- 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 +3 -2
- package/dist/core/components/authentication/AuthPage.js.map +1 -1
- package/dist/core/components/authentication/Signin.d.ts +5 -1
- package/dist/core/components/authentication/Signin.d.ts.map +1 -1
- package/dist/core/components/authentication/Signin.js +17 -6
- package/dist/core/components/authentication/Signin.js.map +1 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.d.ts.map +1 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.js +4 -2
- package/dist/core/components/settings/src/OrganizationSettingsPanel.js.map +1 -1
- package/dist/core/components/ui/AnimatedBackground.d.ts.map +1 -1
- package/dist/core/components/ui/AnimatedBackground.js +3 -1
- package/dist/core/components/ui/AnimatedBackground.js.map +1 -1
- package/dist/core/components/ui/AppSidebar.d.ts.map +1 -1
- package/dist/core/components/ui/AppSidebar.js +11 -11
- package/dist/core/components/ui/AppSidebar.js.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js +3 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js +4 -2
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.js +3 -1
- package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.js +2 -2
- package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.js +3 -5
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js +5 -3
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.js +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.js +4 -2
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.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 +4 -2
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js +7 -5
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js +15 -8
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js.map +1 -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 +13 -12
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
- package/dist/core/store/AppConfig/context.d.ts +10 -1
- package/dist/core/store/AppConfig/context.d.ts.map +1 -1
- package/dist/core/store/AppConfig/context.js +26 -5
- package/dist/core/store/AppConfig/context.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/core/components/settings/src/OrganizationSettingsPanel.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 { useSession } from 'next-auth/react'\r\nimport { toast } from 'sonner'\r\nimport { useTranslations } from 'next-intl'\r\nimport { MapContext, usePermissions } from '../../../store'\r\nimport * as LR from 'lucide-react'\r\n\r\nimport type { Organization } from '../../../types/dbTypes'\r\nimport { Button } from '../../ui/Button'\r\nimport { Input } from '../../ui/Input'\r\nimport { Textarea } from '../../ui/Textarea'\r\nimport { Separator } from '../../ui/Separator'\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from '../../ui/Select'\r\nimport { uploadOrganizationLogoToPublicBucket } from '../../../utils/imageUtils'\r\nimport { useOrganization } from '../../../hooks/organizations/organizations'\r\nimport OrganizationSkeleton from './OrganizationSkeleton'\r\n\r\nexport default function OrganizationSettingsPanel() {\r\n const t = useTranslations('OrganizationSettings')\r\n\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const { data: session } = useSession()\r\n\r\n const {state: mapState} = React.useContext(MapContext)\r\n const { countrySubdivisionsData } = mapState.map;\r\n\r\n const user = session?.user\r\n const userOrganizationId = user?.organizationId\r\n const {\r\n organization: organizationData,\r\n isLoading: isOrganizationLoading,\r\n } = useOrganization(userOrganizationId ? String(userOrganizationId) : null)\r\n\r\n const [organization, setOrganization] = React.useState<Organization | null>(organizationData ?? null)\r\n const [editingValues, setEditingValues] = React.useState<Partial<Organization>>({})\r\n const [isEditing, setIsEditing] = React.useState(false)\r\n const [hasChanges, setHasChanges] = React.useState(false)\r\n const [selectedLogoFile, setSelectedLogoFile] = React.useState<File | null>(null)\r\n const [selectedFaviconFile, setSelectedFaviconFile] = React.useState<File | null>(null)\r\n\r\n React.useEffect(() => {\r\n if (organizationData) {\r\n setOrganization(organizationData)\r\n }\r\n }, [organizationData])\r\n\r\n const handleInputChange = (key: keyof Organization, value: any) => {\r\n setEditingValues(prev => ({\r\n ...prev,\r\n [key]: value,\r\n }))\r\n setHasChanges(true)\r\n }\r\n\r\n const getFieldValue = (property: keyof Organization) => {\r\n return Object.prototype.hasOwnProperty.call(editingValues, property)\r\n ? editingValues[property]\r\n : organization?.[property]\r\n }\r\n\r\n const handleSave = async () => {\r\n if (!organization) return\r\n\r\n try {\r\n const patch: Partial<Organization> = {\r\n ...editingValues,\r\n }\r\n\r\n // Upload logo if changed\r\n if (selectedLogoFile) {\r\n const logoKey = await uploadOrganizationLogoToPublicBucket(selectedLogoFile)\r\n patch.logoKey = logoKey\r\n }\r\n\r\n // Upload favicon if changed\r\n if (selectedFaviconFile) {\r\n const faviconKey = await uploadOrganizationLogoToPublicBucket(selectedFaviconFile)\r\n patch.faviconKey = faviconKey\r\n }\r\n\r\n const res = await fetch(`/api/organizations/${organization.id}`, {\r\n method: 'PATCH',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(patch),\r\n })\r\n\r\n if (!res.ok) throw new Error('Failed to update organization')\r\n\r\n const responseData = await res.json()\r\n const updatedOrg = responseData?.organization ?? responseData\r\n setOrganization(updatedOrg)\r\n setEditingValues({})\r\n setIsEditing(false)\r\n setHasChanges(false)\r\n setSelectedLogoFile(null)\r\n setSelectedFaviconFile(null)\r\n toast.success('Organization updated successfully')\r\n } catch (error) {\r\n toast.error('Failed to update organization')\r\n }\r\n }\r\n\r\n const handleCancel = () => {\r\n setEditingValues({})\r\n setIsEditing(false)\r\n setHasChanges(false)\r\n setSelectedLogoFile(null)\r\n setSelectedFaviconFile(null)\r\n }\r\n\r\n const logoUrl = selectedLogoFile\r\n ? URL.createObjectURL(selectedLogoFile)\r\n : organization?.logoKey\r\n ? `${process.env.NEXT_PUBLIC_MINIO_BUCKET_URL}/org-logos/${organization.logoKey}`\r\n : null\r\n\r\n const faviconUrl = selectedFaviconFile\r\n ? URL.createObjectURL(selectedFaviconFile)\r\n : organization?.faviconKey\r\n ? `${process.env.NEXT_PUBLIC_MINIO_BUCKET_URL}/org-logos/${organization.faviconKey}`\r\n : null\r\n\r\n if (isOrganizationLoading) {\r\n return (\r\n <OrganizationSkeleton />\r\n )\r\n }\r\n\r\n if (!organization) {\r\n return (\r\n <div className=\"flex items-center justify-center h-full\">\r\n <p className=\"text-muted-foreground\">{t('messages.noOrganization')}</p>\r\n </div>\r\n )\r\n }\r\n\r\n const countrySubdivisions = \r\n countrySubdivisionsData\r\n ? Object.values(countrySubdivisionsData).map((subdivision: any) => subdivision.name)\r\n : []\r\n\r\n return (\r\n <div className=\"flex flex-col h-full overflow-hidden\">\r\n {/* Header */}\r\n <div className=\"flex justify-between items-center px-6 py-4 border-b\">\r\n <div>\r\n <h2 className=\"text-2xl font-semibold\">{t('header')}</h2>\r\n <p className=\"text-sm text-muted-foreground\">{t('subheader')}</p>\r\n </div>\r\n <div className=\"flex gap-2\">\r\n {isEditing ? (\r\n <>\r\n <Button variant=\"outline\" onClick={handleCancel} disabled={!ability.can('update', \"Organization\")}>\r\n {t('cancel')}\r\n </Button>\r\n <Button onClick={handleSave} disabled={!hasChanges || !ability.can('update', \"Organization\")}>\r\n <LR.Save className=\"mr-2\" />\r\n {t('save')}\r\n </Button>\r\n </>\r\n ) : (\r\n <Button onClick={() => setIsEditing(true)} disabled={!ability.can('update', \"Organization\")}>\r\n <LR.Pencil className=\"mr-2\" />\r\n {t('edit')}\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"flex-1 overflow-auto p-6\">\r\n <div className=\"max-w-4xl mx-auto space-y-8\">\r\n {/* Branding Section */}\r\n <div className=\"space-y-4\">\r\n <h3 className=\"text-lg font-semibold\">{t('sections.branding')}</h3>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n {/* Logo */}\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.logo')}</label>\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"w-32 h-32 border rounded-lg overflow-hidden bg-muted flex items-center justify-center relative group\">\r\n {logoUrl ? (\r\n <img src={logoUrl} alt=\"Organization logo\" className=\"w-full h-full object-contain\" />\r\n ) : (\r\n <LR.Building2 className=\"h-12 w-12 text-muted-foreground\" />\r\n )}\r\n {isEditing && (\r\n <label className=\"absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center cursor-pointer\">\r\n <LR.Upload className=\"h-6 w-6 text-white\" />\r\n <input\r\n type=\"file\"\r\n accept=\"image/*\"\r\n className=\"hidden\"\r\n onChange={(e) => {\r\n const file = e.target.files?.[0]\r\n if (file) {\r\n setSelectedLogoFile(file)\r\n setHasChanges(true)\r\n }\r\n }}\r\n disabled={!ability.can('update', \"Organization\")}\r\n />\r\n </label>\r\n )}\r\n </div>\r\n {isEditing && logoUrl && (\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={() => {\r\n setSelectedLogoFile(null)\r\n handleInputChange('logoKey', null)\r\n }}\r\n disabled={!ability.can('update', \"Organization\")}\r\n >\r\n Remove\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Favicon */}\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.favicon')}</label>\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"w-16 h-16 border rounded-lg overflow-hidden bg-muted flex items-center justify-center relative group\">\r\n {faviconUrl ? (\r\n <img src={faviconUrl} alt=\"Favicon\" className=\"w-full h-full object-contain\" />\r\n ) : (\r\n <LR.Image className=\"h-6 w-6 text-muted-foreground\" />\r\n )}\r\n {isEditing && (\r\n <label className=\"absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center cursor-pointer\">\r\n <LR.Upload className=\"h-4 w-4 text-white\" />\r\n <input\r\n type=\"file\"\r\n accept=\"image/*\"\r\n className=\"hidden\"\r\n onChange={(e) => {\r\n const file = e.target.files?.[0]\r\n if (file) {\r\n setSelectedFaviconFile(file)\r\n setHasChanges(true)\r\n }\r\n }}\r\n disabled={!ability.can('update', \"Organization\")}\r\n />\r\n </label>\r\n )}\r\n </div>\r\n {isEditing && faviconUrl && (\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={() => {\r\n setSelectedFaviconFile(null)\r\n handleInputChange('faviconKey', null)\r\n }}\r\n disabled={!ability.can('update', \"Organization\")}\r\n >\r\n Remove\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Colors */}\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.mainColor')}</label>\r\n <div className=\"flex gap-2\">\r\n <Input\r\n type=\"color\"\r\n value={(getFieldValue('mainColor') as string) || '#000000'}\r\n onChange={(e) => handleInputChange('mainColor', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n className=\"w-20 h-10 p-1\"\r\n \r\n />\r\n <Input\r\n type=\"text\"\r\n value={(getFieldValue('mainColor') as string) || ''}\r\n onChange={(e) => handleInputChange('mainColor', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n placeholder=\"#000000\"\r\n />\r\n </div>\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.secondaryColor')}</label>\r\n <div className=\"flex gap-2\">\r\n <Input\r\n type=\"color\"\r\n value={(getFieldValue('secondaryColor') as string) || '#000000'}\r\n onChange={(e) => handleInputChange('secondaryColor', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n className=\"w-20 h-10 p-1\"\r\n />\r\n <Input\r\n type=\"text\"\r\n value={(getFieldValue('secondaryColor') as string) || ''}\r\n onChange={(e) => handleInputChange('secondaryColor', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n placeholder=\"#000000\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <Separator />\r\n\r\n {/* Basic Information */}\r\n <div className=\"space-y-4\">\r\n <h3 className=\"text-lg font-semibold\">{t('sections.basicInfo')}</h3>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.name')}</label>\r\n <Input\r\n value={(getFieldValue('name') as string) || ''}\r\n onChange={(e) => handleInputChange('name', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.title')}</label>\r\n <Input\r\n value={(getFieldValue('title') as string) || ''}\r\n onChange={(e) => handleInputChange('title', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\") }\r\n />\r\n </div>\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.description')}</label>\r\n <Textarea\r\n value={(getFieldValue('description') as string) || ''}\r\n onChange={(e) => handleInputChange('description', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n rows={4}\r\n />\r\n </div>\r\n </div>\r\n\r\n <Separator />\r\n\r\n {/* Location */}\r\n <div className=\"space-y-4\">\r\n <h3 className=\"text-lg font-semibold\">{t('sections.location')}</h3>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.countrySubdivision')}</label>\r\n <Select\r\n value={String(getFieldValue('countrySubdivision') || '')}\r\n onValueChange={(value) => handleInputChange('countrySubdivision', value)}\r\n disabled={!isEditing}\r\n >\r\n <SelectTrigger>\r\n <SelectValue placeholder={t('placeholders.selectProvince')} />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {countrySubdivisions.map((csName) => (\r\n <SelectItem key={csName} value={csName}>\r\n {csName}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.municipality')}</label>\r\n <Input\r\n value={(getFieldValue('municipality') as string) || ''}\r\n onChange={(e) => handleInputChange('municipality', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.postalCode')}</label>\r\n <Input\r\n value={(getFieldValue('postalCode') as string) || ''}\r\n onChange={(e) => handleInputChange('postalCode', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.locationId')}</label>\r\n <Input\r\n value={(getFieldValue('locationId') as string) || ''}\r\n onChange={(e) => handleInputChange('locationId', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <Separator />\r\n\r\n {/* Map Configuration */}\r\n <div className=\"space-y-4\">\r\n <h3 className=\"text-lg font-semibold\">{t('sections.mapConfig')}</h3>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.latitude')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('lat') as number) ?? ''}\r\n onChange={(e) => handleInputChange('lat', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.longitude')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('long') as number) ?? ''}\r\n onChange={(e) => handleInputChange('long', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.zoom')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('zoom') as number) ?? ''}\r\n onChange={(e) => handleInputChange('zoom', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.minZoom')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('minZoom') as number) ?? ''}\r\n onChange={(e) => handleInputChange('minZoom', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.bearing')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('bearing') as number) ?? ''}\r\n onChange={(e) => handleInputChange('bearing', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.pitch')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('pitch') as number) ?? ''}\r\n onChange={(e) => handleInputChange('pitch', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyIM,SA2BM,UA3BN,KAqBE,YArBF;AApIN,YAAY,WAAW;AACvB,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,SAAS,YAAY,sBAAsB;AAC3C,YAAY,QAAQ;AAGpB,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,4CAA4C;AACrD,SAAS,uBAAuB;AAChC,OAAO,0BAA0B;AAElB,SAAR,4BAA6C;AA5BpD;AA6BE,QAAM,IAAI,gBAAgB,sBAAsB;AAGhD,QAAM,EAAE,QAAQ,IAAI,eAAe;AAEnC,QAAM,EAAE,MAAM,QAAQ,IAAI,WAAW;AAErC,QAAM,EAAC,OAAO,SAAQ,IAAI,MAAM,WAAW,UAAU;AACrD,QAAM,EAAE,wBAAwB,IAAI,SAAS;AAE7C,QAAM,OAAO,mCAAS;AACtB,QAAM,qBAAqB,6BAAM;AACjC,QAAM;AAAA,IACJ,cAAc;AAAA,IACd,WAAW;AAAA,EACb,IAAI,gBAAgB,qBAAqB,OAAO,kBAAkB,IAAI,IAAI;AAE1E,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAA8B,8CAAoB,IAAI;AACpG,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAgC,CAAC,CAAC;AAClF,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AACtD,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAsB,IAAI;AAChF,QAAM,CAAC,qBAAqB,sBAAsB,IAAI,MAAM,SAAsB,IAAI;AAEtF,QAAM,UAAU,MAAM;AACpB,QAAI,kBAAkB;AACpB,sBAAgB,gBAAgB;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,gBAAgB,CAAC;AAErB,QAAM,oBAAoB,CAAC,KAAyB,UAAe;AACjE,qBAAiB,UAAS,iCACrB,OADqB;AAAA,MAExB,CAAC,GAAG,GAAG;AAAA,IACT,EAAE;AACF,kBAAc,IAAI;AAAA,EACpB;AAEA,QAAM,gBAAgB,CAAC,aAAiC;AACtD,WAAO,OAAO,UAAU,eAAe,KAAK,eAAe,QAAQ,IAC/D,cAAc,QAAQ,IACtB,6CAAe;AAAA,EACrB;AAEA,QAAM,aAAa,YAAY;AAzEjC,QAAAA;AA0EI,QAAI,CAAC,aAAc;AAEnB,QAAI;AACF,YAAM,QAA+B,mBAChC;AAIL,UAAI,kBAAkB;AACpB,cAAM,UAAU,MAAM,qCAAqC,gBAAgB;AAC3E,cAAM,UAAU;AAAA,MAClB;AAGA,UAAI,qBAAqB;AACvB,cAAM,aAAa,MAAM,qCAAqC,mBAAmB;AACjF,cAAM,aAAa;AAAA,MACrB;AAEA,YAAM,MAAM,MAAM,MAAM,sBAAsB,aAAa,EAAE,IAAI;AAAA,QAC/D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,KAAK;AAAA,MAC5B,CAAC;AAED,UAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,+BAA+B;AAE5D,YAAM,eAAe,MAAM,IAAI,KAAK;AACpC,YAAM,cAAaA,MAAA,6CAAc,iBAAd,OAAAA,MAA8B;AACjD,sBAAgB,UAAU;AAC1B,uBAAiB,CAAC,CAAC;AACnB,mBAAa,KAAK;AAClB,oBAAc,KAAK;AACnB,0BAAoB,IAAI;AACxB,6BAAuB,IAAI;AAC3B,YAAM,QAAQ,mCAAmC;AAAA,IACnD,SAAS,OAAO;AACd,YAAM,MAAM,+BAA+B;AAAA,IAC7C;AAAA,EACF;AAEA,QAAM,eAAe,MAAM;AACzB,qBAAiB,CAAC,CAAC;AACnB,iBAAa,KAAK;AAClB,kBAAc,KAAK;AACnB,wBAAoB,IAAI;AACxB,2BAAuB,IAAI;AAAA,EAC7B;AAEA,QAAM,UAAU,mBACZ,IAAI,gBAAgB,gBAAgB,KACpC,6CAAc,WACZ,GAAG,QAAQ,IAAI,4BAA4B,cAAc,aAAa,OAAO,KAC7E;AAEN,QAAM,aAAa,sBACf,IAAI,gBAAgB,mBAAmB,KACvC,6CAAc,cACZ,GAAG,QAAQ,IAAI,4BAA4B,cAAc,aAAa,UAAU,KAChF;AAEN,MAAI,uBAAuB;AACzB,WACE,oBAAC,wBAAqB;AAAA,EAE1B;AAEA,MAAI,CAAC,cAAc;AACjB,WACE,oBAAC,SAAI,WAAU,2CACb,8BAAC,OAAE,WAAU,yBAAyB,YAAE,yBAAyB,GAAE,GACrE;AAAA,EAEJ;AAEA,QAAM,sBACN,0BACI,OAAO,OAAO,uBAAuB,EAAE,IAAI,CAAC,gBAAqB,YAAY,IAAI,IACjF,CAAC;AAEL,SACE,qBAAC,SAAI,WAAU,wCAEb;AAAA,yBAAC,SAAI,WAAU,wDACb;AAAA,2BAAC,SACC;AAAA,4BAAC,QAAG,WAAU,0BAA0B,YAAE,QAAQ,GAAE;AAAA,QACpD,oBAAC,OAAE,WAAU,iCAAiC,YAAE,WAAW,GAAE;AAAA,SAC/D;AAAA,MACA,oBAAC,SAAI,WAAU,cACZ,sBACC,iCACE;AAAA,4BAAC,UAAO,SAAQ,WAAU,SAAS,cAAc,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc,GAC7F,YAAE,QAAQ,GACb;AAAA,QACA,qBAAC,UAAO,SAAS,YAAY,UAAU,CAAC,cAAc,CAAC,QAAQ,IAAI,UAAU,cAAc,GACzF;AAAA,8BAAC,GAAG,MAAH,EAAQ,WAAU,QAAO;AAAA,UACzB,EAAE,MAAM;AAAA,WACX;AAAA,SACF,IAEA,qBAAC,UAAO,SAAS,MAAM,aAAa,IAAI,GAAG,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc,GACxF;AAAA,4BAAC,GAAG,QAAH,EAAU,WAAU,QAAO;AAAA,QAC3B,EAAE,MAAM;AAAA,SACX,GAEJ;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,4BACb,+BAAC,SAAI,WAAU,+BAEb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,QAAG,WAAU,yBAAyB,YAAE,mBAAmB,GAAE;AAAA,QAC9D,qBAAC,SAAI,WAAU,yCAEb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,aAAa,GAAE;AAAA,YACzD,qBAAC,SAAI,WAAU,2BACb;AAAA,mCAAC,SAAI,WAAU,wGACZ;AAAA,0BACC,oBAAC,SAAI,KAAK,SAAS,KAAI,qBAAoB,WAAU,gCAA+B,IAEpF,oBAAC,GAAG,WAAH,EAAa,WAAU,mCAAkC;AAAA,gBAE3D,aACC,qBAAC,WAAM,WAAU,qIACf;AAAA,sCAAC,GAAG,QAAH,EAAU,WAAU,sBAAqB;AAAA,kBAC1C;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,QAAO;AAAA,sBACP,WAAU;AAAA,sBACV,UAAU,CAAC,MAAM;AA9M3C,4BAAAA;AA+M4B,8BAAM,QAAOA,MAAA,EAAE,OAAO,UAAT,gBAAAA,IAAiB;AAC9B,4BAAI,MAAM;AACR,8CAAoB,IAAI;AACxB,wCAAc,IAAI;AAAA,wBACpB;AAAA,sBACF;AAAA,sBACA,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,kBACjD;AAAA,mBACF;AAAA,iBAEJ;AAAA,cACC,aAAa,WACZ;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,SAAS,MAAM;AACb,wCAAoB,IAAI;AACxB,sCAAkB,WAAW,IAAI;AAAA,kBACnC;AAAA,kBACA,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAChD;AAAA;AAAA,cAED;AAAA,eAEJ;AAAA,aACF;AAAA,UAGA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,gBAAgB,GAAE;AAAA,YAC5D,qBAAC,SAAI,WAAU,2BACb;AAAA,mCAAC,SAAI,WAAU,wGACZ;AAAA,6BACC,oBAAC,SAAI,KAAK,YAAY,KAAI,WAAU,WAAU,gCAA+B,IAE7E,oBAAC,GAAG,OAAH,EAAS,WAAU,iCAAgC;AAAA,gBAErD,aACC,qBAAC,WAAM,WAAU,qIACf;AAAA,sCAAC,GAAG,QAAH,EAAU,WAAU,sBAAqB;AAAA,kBAC1C;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,QAAO;AAAA,sBACP,WAAU;AAAA,sBACV,UAAU,CAAC,MAAM;AA3P3C,4BAAAA;AA4P4B,8BAAM,QAAOA,MAAA,EAAE,OAAO,UAAT,gBAAAA,IAAiB;AAC9B,4BAAI,MAAM;AACR,iDAAuB,IAAI;AAC3B,wCAAc,IAAI;AAAA,wBACpB;AAAA,sBACF;AAAA,sBACA,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,kBACjD;AAAA,mBACF;AAAA,iBAEJ;AAAA,cACC,aAAa,cACZ;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,SAAS,MAAM;AACb,2CAAuB,IAAI;AAC3B,sCAAkB,cAAc,IAAI;AAAA,kBACtC;AAAA,kBACA,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAChD;AAAA;AAAA,cAED;AAAA,eAEJ;AAAA,aACF;AAAA,WACF;AAAA,QAGA,qBAAC,SAAI,WAAU,yCACb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,kBAAkB,GAAE;AAAA,YAC9D,qBAAC,SAAI,WAAU,cACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAQ,cAAc,WAAW,KAAgB;AAAA,kBACjD,UAAU,CAAC,MAAM,kBAAkB,aAAa,EAAE,OAAO,KAAK;AAAA,kBAC9D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAC7D,WAAU;AAAA;AAAA,cAEZ;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAQ,cAAc,WAAW,KAAgB;AAAA,kBACjD,UAAU,CAAC,MAAM,kBAAkB,aAAa,EAAE,OAAO,KAAK;AAAA,kBAC9D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAC7D,aAAY;AAAA;AAAA,cACd;AAAA,eACF;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,uBAAuB,GAAE;AAAA,YACnE,qBAAC,SAAI,WAAU,cACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAQ,cAAc,gBAAgB,KAAgB;AAAA,kBACtD,UAAU,CAAC,MAAM,kBAAkB,kBAAkB,EAAE,OAAO,KAAK;AAAA,kBACnE,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAC7D,WAAU;AAAA;AAAA,cACZ;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAQ,cAAc,gBAAgB,KAAgB;AAAA,kBACtD,UAAU,CAAC,MAAM,kBAAkB,kBAAkB,EAAE,OAAO,KAAK;AAAA,kBACnE,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAC7D,aAAY;AAAA;AAAA,cACd;AAAA,eACF;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,MAEA,oBAAC,aAAU;AAAA,MAGX,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,QAAG,WAAU,yBAAyB,YAAE,oBAAoB,GAAE;AAAA,QAC/D,qBAAC,SAAI,WAAU,yCACb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,aAAa,GAAE;AAAA,YACzD;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,MAAM,KAAgB;AAAA,gBAC5C,UAAU,CAAC,MAAM,kBAAkB,QAAQ,EAAE,OAAO,KAAK;AAAA,gBACzD,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,cAAc,GAAE;AAAA,YAC1D;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,OAAO,KAAgB;AAAA,gBAC7C,UAAU,CAAC,MAAM,kBAAkB,SAAS,EAAE,OAAO,KAAK;AAAA,gBAC1D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAU,aACb;AAAA,8BAAC,WAAM,WAAU,uBAAuB,YAAE,oBAAoB,GAAE;AAAA,UAChE;AAAA,YAAC;AAAA;AAAA,cACC,OAAQ,cAAc,aAAa,KAAgB;AAAA,cACnD,UAAU,CAAC,MAAM,kBAAkB,eAAe,EAAE,OAAO,KAAK;AAAA,cAChE,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,cAC7D,MAAM;AAAA;AAAA,UACR;AAAA,WACF;AAAA,SACF;AAAA,MAEA,oBAAC,aAAU;AAAA,MAGX,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,QAAG,WAAU,yBAAyB,YAAE,mBAAmB,GAAE;AAAA,QAC9D,qBAAC,SAAI,WAAU,yCACb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,2BAA2B,GAAE;AAAA,YACvE;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO,OAAO,cAAc,oBAAoB,KAAK,EAAE;AAAA,gBACvD,eAAe,CAAC,UAAU,kBAAkB,sBAAsB,KAAK;AAAA,gBACvE,UAAU,CAAC;AAAA,gBAEX;AAAA,sCAAC,iBACC,8BAAC,eAAY,aAAa,EAAE,6BAA6B,GAAG,GAC9D;AAAA,kBACA,oBAAC,iBACE,8BAAoB,IAAI,CAAC,WACxB,oBAAC,cAAwB,OAAO,QAC7B,oBADc,MAEjB,CACD,GACH;AAAA;AAAA;AAAA,YACF;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,qBAAqB,GAAE;AAAA,YACjE;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,cAAc,KAAgB;AAAA,gBACpD,UAAU,CAAC,MAAM,kBAAkB,gBAAgB,EAAE,OAAO,KAAK;AAAA,gBACjE,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,mBAAmB,GAAE;AAAA,YAC/D;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,YAAY,KAAgB;AAAA,gBAClD,UAAU,CAAC,MAAM,kBAAkB,cAAc,EAAE,OAAO,KAAK;AAAA,gBAC/D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,mBAAmB,GAAE;AAAA,YAC/D;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,YAAY,KAAgB;AAAA,gBAClD,UAAU,CAAC,MAAM,kBAAkB,cAAc,EAAE,OAAO,KAAK;AAAA,gBAC/D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,MAEA,oBAAC,aAAU;AAAA,MAGX,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,QAAG,WAAU,yBAAyB,YAAE,oBAAoB,GAAE;AAAA,QAC/D,qBAAC,SAAI,WAAU,wDACb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,iBAAiB,GAAE;AAAA,YAC7D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,KAAK,MAAnB,YAAmC;AAAA,gBAC3C,UAAU,CAAC,MAAM,kBAAkB,OAAO,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAC5F,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,kBAAkB,GAAE;AAAA,YAC9D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,MAAM,MAApB,YAAoC;AAAA,gBAC5C,UAAU,CAAC,MAAM,kBAAkB,QAAQ,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAC7F,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,aAAa,GAAE;AAAA,YACzD;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,MAAM,MAApB,YAAoC;AAAA,gBAC5C,UAAU,CAAC,MAAM,kBAAkB,QAAQ,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAC7F,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,gBAAgB,GAAE;AAAA,YAC5D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,SAAS,MAAvB,YAAuC;AAAA,gBAC/C,UAAU,CAAC,MAAM,kBAAkB,WAAW,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAChG,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,gBAAgB,GAAE;AAAA,YAC5D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,SAAS,MAAvB,YAAuC;AAAA,gBAC/C,UAAU,CAAC,MAAM,kBAAkB,WAAW,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAChG,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,cAAc,GAAE;AAAA,YAC1D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,OAAO,MAArB,YAAqC;AAAA,gBAC7C,UAAU,CAAC,MAAM,kBAAkB,SAAS,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAC9F,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,OACF,GACF;AAAA,KACF;AAEJ;","names":["_a"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/core/components/settings/src/OrganizationSettingsPanel.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 { useSession } from 'next-auth/react'\r\nimport { toast } from 'sonner'\r\nimport { useTranslations } from 'next-intl'\r\nimport { MapContext, usePermissions } from '../../../store'\r\nimport * as LR from 'lucide-react'\r\n\r\nimport type { Organization } from '../../../types/dbTypes'\r\nimport { Button } from '../../ui/Button'\r\nimport { Input } from '../../ui/Input'\r\nimport { Textarea } from '../../ui/Textarea'\r\nimport { Separator } from '../../ui/Separator'\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from '../../ui/Select'\r\nimport { uploadOrganizationLogoToPublicBucket } from '../../../utils/imageUtils'\r\nimport { useOrganization } from '../../../hooks/organizations/organizations'\r\nimport OrganizationSkeleton from './OrganizationSkeleton'\r\n\r\nimport { useAppConfigContext } from '../../../store/AppConfig/context'\r\n\r\nexport default function OrganizationSettingsPanel() {\r\n const t = useTranslations('OrganizationSettings')\r\n\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const { data: session } = useSession()\r\n\r\n const {state: mapState} = React.useContext(MapContext)\r\n const { countrySubdivisionsData } = mapState.map;\r\n\r\n const user = session?.user\r\n const userOrganizationId = user?.organizationId\r\n const {\r\n organization: organizationData,\r\n isLoading: isOrganizationLoading,\r\n } = useOrganization(userOrganizationId ? String(userOrganizationId) : null)\r\n\r\n const [organization, setOrganization] = React.useState<Organization | null>(organizationData ?? null)\r\n const [editingValues, setEditingValues] = React.useState<Partial<Organization>>({})\r\n const [isEditing, setIsEditing] = React.useState(false)\r\n const [hasChanges, setHasChanges] = React.useState(false)\r\n const [selectedLogoFile, setSelectedLogoFile] = React.useState<File | null>(null)\r\n const [selectedFaviconFile, setSelectedFaviconFile] = React.useState<File | null>(null)\r\n\r\n React.useEffect(() => {\r\n if (organizationData) {\r\n setOrganization(organizationData)\r\n }\r\n }, [organizationData])\r\n\r\n const handleInputChange = (key: keyof Organization, value: any) => {\r\n setEditingValues(prev => ({\r\n ...prev,\r\n [key]: value,\r\n }))\r\n setHasChanges(true)\r\n }\r\n\r\n const getFieldValue = (property: keyof Organization) => {\r\n return Object.prototype.hasOwnProperty.call(editingValues, property)\r\n ? editingValues[property]\r\n : organization?.[property]\r\n }\r\n\r\n const handleSave = async () => {\r\n if (!organization) return\r\n\r\n try {\r\n const patch: Partial<Organization> = {\r\n ...editingValues,\r\n }\r\n\r\n // Upload logo if changed\r\n if (selectedLogoFile) {\r\n const logoKey = await uploadOrganizationLogoToPublicBucket(selectedLogoFile)\r\n patch.logoKey = logoKey\r\n }\r\n\r\n // Upload favicon if changed\r\n if (selectedFaviconFile) {\r\n const faviconKey = await uploadOrganizationLogoToPublicBucket(selectedFaviconFile)\r\n patch.faviconKey = faviconKey\r\n }\r\n\r\n const res = await fetch(`/api/organizations/${organization.id}`, {\r\n method: 'PATCH',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(patch),\r\n })\r\n\r\n if (!res.ok) throw new Error('Failed to update organization')\r\n\r\n const responseData = await res.json()\r\n const updatedOrg = responseData?.organization ?? responseData\r\n setOrganization(updatedOrg)\r\n setEditingValues({})\r\n setIsEditing(false)\r\n setHasChanges(false)\r\n setSelectedLogoFile(null)\r\n setSelectedFaviconFile(null)\r\n toast.success('Organization updated successfully')\r\n } catch (error) {\r\n toast.error('Failed to update organization')\r\n }\r\n }\r\n\r\n const handleCancel = () => {\r\n setEditingValues({})\r\n setIsEditing(false)\r\n setHasChanges(false)\r\n setSelectedLogoFile(null)\r\n setSelectedFaviconFile(null)\r\n }\r\n\r\n const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext()\r\n\r\n const logoUrl = selectedLogoFile\r\n ? URL.createObjectURL(selectedLogoFile)\r\n : organization?.logoKey && minioUrl\r\n ? `${minioUrl}/org-logos/${organization.logoKey}`\r\n : null\r\n\r\n const faviconUrl = selectedFaviconFile\r\n ? URL.createObjectURL(selectedFaviconFile)\r\n : organization?.faviconKey && minioUrl\r\n ? `${minioUrl}/org-logos/${organization.faviconKey}`\r\n : null\r\n\r\n// const faviconUrl = selectedFaviconFile\r\n// ? URL.createObjectURL(selectedFaviconFile)\r\n// : organization?.faviconKey && minioUrl\r\n// ? `${minioUrl}/org-logos/${organization.faviconKey}`\r\n// : null\r\n \r\n if (isOrganizationLoading) {\r\n return (\r\n <OrganizationSkeleton />\r\n )\r\n }\r\n\r\n if (!organization) {\r\n return (\r\n <div className=\"flex items-center justify-center h-full\">\r\n <p className=\"text-muted-foreground\">{t('messages.noOrganization')}</p>\r\n </div>\r\n )\r\n }\r\n\r\n const countrySubdivisions = \r\n countrySubdivisionsData\r\n ? Object.values(countrySubdivisionsData).map((subdivision: any) => subdivision.name)\r\n : []\r\n\r\n return (\r\n <div className=\"flex flex-col h-full overflow-hidden\">\r\n {/* Header */}\r\n <div className=\"flex justify-between items-center px-6 py-4 border-b\">\r\n <div>\r\n <h2 className=\"text-2xl font-semibold\">{t('header')}</h2>\r\n <p className=\"text-sm text-muted-foreground\">{t('subheader')}</p>\r\n </div>\r\n <div className=\"flex gap-2\">\r\n {isEditing ? (\r\n <>\r\n <Button variant=\"outline\" onClick={handleCancel} disabled={!ability.can('update', \"Organization\")}>\r\n {t('cancel')}\r\n </Button>\r\n <Button onClick={handleSave} disabled={!hasChanges || !ability.can('update', \"Organization\")}>\r\n <LR.Save className=\"mr-2\" />\r\n {t('save')}\r\n </Button>\r\n </>\r\n ) : (\r\n <Button onClick={() => setIsEditing(true)} disabled={!ability.can('update', \"Organization\")}>\r\n <LR.Pencil className=\"mr-2\" />\r\n {t('edit')}\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"flex-1 overflow-auto p-6\">\r\n <div className=\"max-w-4xl mx-auto space-y-8\">\r\n {/* Branding Section */}\r\n <div className=\"space-y-4\">\r\n <h3 className=\"text-lg font-semibold\">{t('sections.branding')}</h3>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n {/* Logo */}\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.logo')}</label>\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"w-32 h-32 border rounded-lg overflow-hidden bg-muted flex items-center justify-center relative group\">\r\n {logoUrl ? (\r\n <img src={logoUrl} alt=\"Organization logo\" className=\"w-full h-full object-contain\" />\r\n ) : (\r\n <LR.Building2 className=\"h-12 w-12 text-muted-foreground\" />\r\n )}\r\n {isEditing && (\r\n <label className=\"absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center cursor-pointer\">\r\n <LR.Upload className=\"h-6 w-6 text-white\" />\r\n <input\r\n type=\"file\"\r\n accept=\"image/*\"\r\n className=\"hidden\"\r\n onChange={(e) => {\r\n const file = e.target.files?.[0]\r\n if (file) {\r\n setSelectedLogoFile(file)\r\n setHasChanges(true)\r\n }\r\n }}\r\n disabled={!ability.can('update', \"Organization\")}\r\n />\r\n </label>\r\n )}\r\n </div>\r\n {isEditing && logoUrl && (\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={() => {\r\n setSelectedLogoFile(null)\r\n handleInputChange('logoKey', null)\r\n }}\r\n disabled={!ability.can('update', \"Organization\")}\r\n >\r\n Remove\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Favicon */}\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.favicon')}</label>\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"w-16 h-16 border rounded-lg overflow-hidden bg-muted flex items-center justify-center relative group\">\r\n {faviconUrl ? (\r\n <img src={faviconUrl} alt=\"Favicon\" className=\"w-full h-full object-contain\" />\r\n ) : (\r\n <LR.Image className=\"h-6 w-6 text-muted-foreground\" />\r\n )}\r\n {isEditing && (\r\n <label className=\"absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center cursor-pointer\">\r\n <LR.Upload className=\"h-4 w-4 text-white\" />\r\n <input\r\n type=\"file\"\r\n accept=\"image/*\"\r\n className=\"hidden\"\r\n onChange={(e) => {\r\n const file = e.target.files?.[0]\r\n if (file) {\r\n setSelectedFaviconFile(file)\r\n setHasChanges(true)\r\n }\r\n }}\r\n disabled={!ability.can('update', \"Organization\")}\r\n />\r\n </label>\r\n )}\r\n </div>\r\n {isEditing && faviconUrl && (\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={() => {\r\n setSelectedFaviconFile(null)\r\n handleInputChange('faviconKey', null)\r\n }}\r\n disabled={!ability.can('update', \"Organization\")}\r\n >\r\n Remove\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Colors */}\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.mainColor')}</label>\r\n <div className=\"flex gap-2\">\r\n <Input\r\n type=\"color\"\r\n value={(getFieldValue('mainColor') as string) || '#000000'}\r\n onChange={(e) => handleInputChange('mainColor', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n className=\"w-20 h-10 p-1\"\r\n \r\n />\r\n <Input\r\n type=\"text\"\r\n value={(getFieldValue('mainColor') as string) || ''}\r\n onChange={(e) => handleInputChange('mainColor', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n placeholder=\"#000000\"\r\n />\r\n </div>\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.secondaryColor')}</label>\r\n <div className=\"flex gap-2\">\r\n <Input\r\n type=\"color\"\r\n value={(getFieldValue('secondaryColor') as string) || '#000000'}\r\n onChange={(e) => handleInputChange('secondaryColor', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n className=\"w-20 h-10 p-1\"\r\n />\r\n <Input\r\n type=\"text\"\r\n value={(getFieldValue('secondaryColor') as string) || ''}\r\n onChange={(e) => handleInputChange('secondaryColor', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n placeholder=\"#000000\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <Separator />\r\n\r\n {/* Basic Information */}\r\n <div className=\"space-y-4\">\r\n <h3 className=\"text-lg font-semibold\">{t('sections.basicInfo')}</h3>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.name')}</label>\r\n <Input\r\n value={(getFieldValue('name') as string) || ''}\r\n onChange={(e) => handleInputChange('name', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.title')}</label>\r\n <Input\r\n value={(getFieldValue('title') as string) || ''}\r\n onChange={(e) => handleInputChange('title', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\") }\r\n />\r\n </div>\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.description')}</label>\r\n <Textarea\r\n value={(getFieldValue('description') as string) || ''}\r\n onChange={(e) => handleInputChange('description', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n rows={4}\r\n />\r\n </div>\r\n </div>\r\n\r\n <Separator />\r\n\r\n {/* Location */}\r\n <div className=\"space-y-4\">\r\n <h3 className=\"text-lg font-semibold\">{t('sections.location')}</h3>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.countrySubdivision')}</label>\r\n <Select\r\n value={String(getFieldValue('countrySubdivision') || '')}\r\n onValueChange={(value) => handleInputChange('countrySubdivision', value)}\r\n disabled={!isEditing}\r\n >\r\n <SelectTrigger>\r\n <SelectValue placeholder={t('placeholders.selectProvince')} />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {countrySubdivisions.map((csName) => (\r\n <SelectItem key={csName} value={csName}>\r\n {csName}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.municipality')}</label>\r\n <Input\r\n value={(getFieldValue('municipality') as string) || ''}\r\n onChange={(e) => handleInputChange('municipality', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.postalCode')}</label>\r\n <Input\r\n value={(getFieldValue('postalCode') as string) || ''}\r\n onChange={(e) => handleInputChange('postalCode', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.locationId')}</label>\r\n <Input\r\n value={(getFieldValue('locationId') as string) || ''}\r\n onChange={(e) => handleInputChange('locationId', e.target.value)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <Separator />\r\n\r\n {/* Map Configuration */}\r\n <div className=\"space-y-4\">\r\n <h3 className=\"text-lg font-semibold\">{t('sections.mapConfig')}</h3>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.latitude')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('lat') as number) ?? ''}\r\n onChange={(e) => handleInputChange('lat', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.longitude')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('long') as number) ?? ''}\r\n onChange={(e) => handleInputChange('long', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.zoom')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('zoom') as number) ?? ''}\r\n onChange={(e) => handleInputChange('zoom', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.minZoom')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('minZoom') as number) ?? ''}\r\n onChange={(e) => handleInputChange('minZoom', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.bearing')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('bearing') as number) ?? ''}\r\n onChange={(e) => handleInputChange('bearing', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{t('fields.pitch')}</label>\r\n <Input\r\n type=\"number\"\r\n step=\"any\"\r\n value={(getFieldValue('pitch') as number) ?? ''}\r\n onChange={(e) => handleInputChange('pitch', e.target.value ? parseFloat(e.target.value) : null)}\r\n disabled={!isEditing || !ability.can('update', \"Organization\")}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAmJM,SA2BM,UA3BN,KAqBE,YArBF;AA9IN,YAAY,WAAW;AACvB,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,SAAS,YAAY,sBAAsB;AAC3C,YAAY,QAAQ;AAGpB,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,4CAA4C;AACrD,SAAS,uBAAuB;AAChC,OAAO,0BAA0B;AAEjC,SAAS,2BAA2B;AAErB,SAAR,4BAA6C;AA9BpD;AA+BE,QAAM,IAAI,gBAAgB,sBAAsB;AAGhD,QAAM,EAAE,QAAQ,IAAI,eAAe;AAEnC,QAAM,EAAE,MAAM,QAAQ,IAAI,WAAW;AAErC,QAAM,EAAC,OAAO,SAAQ,IAAI,MAAM,WAAW,UAAU;AACrD,QAAM,EAAE,wBAAwB,IAAI,SAAS;AAE7C,QAAM,OAAO,mCAAS;AACtB,QAAM,qBAAqB,6BAAM;AACjC,QAAM;AAAA,IACJ,cAAc;AAAA,IACd,WAAW;AAAA,EACb,IAAI,gBAAgB,qBAAqB,OAAO,kBAAkB,IAAI,IAAI;AAE1E,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAA8B,8CAAoB,IAAI;AACpG,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAgC,CAAC,CAAC;AAClF,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AACtD,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAsB,IAAI;AAChF,QAAM,CAAC,qBAAqB,sBAAsB,IAAI,MAAM,SAAsB,IAAI;AAEtF,QAAM,UAAU,MAAM;AACpB,QAAI,kBAAkB;AACpB,sBAAgB,gBAAgB;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,gBAAgB,CAAC;AAErB,QAAM,oBAAoB,CAAC,KAAyB,UAAe;AACjE,qBAAiB,UAAS,iCACrB,OADqB;AAAA,MAExB,CAAC,GAAG,GAAG;AAAA,IACT,EAAE;AACF,kBAAc,IAAI;AAAA,EACpB;AAEA,QAAM,gBAAgB,CAAC,aAAiC;AACtD,WAAO,OAAO,UAAU,eAAe,KAAK,eAAe,QAAQ,IAC/D,cAAc,QAAQ,IACtB,6CAAe;AAAA,EACrB;AAEA,QAAM,aAAa,YAAY;AA3EjC,QAAAA;AA4EI,QAAI,CAAC,aAAc;AAEnB,QAAI;AACF,YAAM,QAA+B,mBAChC;AAIL,UAAI,kBAAkB;AACpB,cAAM,UAAU,MAAM,qCAAqC,gBAAgB;AAC3E,cAAM,UAAU;AAAA,MAClB;AAGA,UAAI,qBAAqB;AACvB,cAAM,aAAa,MAAM,qCAAqC,mBAAmB;AACjF,cAAM,aAAa;AAAA,MACrB;AAEA,YAAM,MAAM,MAAM,MAAM,sBAAsB,aAAa,EAAE,IAAI;AAAA,QAC/D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,KAAK;AAAA,MAC5B,CAAC;AAED,UAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,+BAA+B;AAE5D,YAAM,eAAe,MAAM,IAAI,KAAK;AACpC,YAAM,cAAaA,MAAA,6CAAc,iBAAd,OAAAA,MAA8B;AACjD,sBAAgB,UAAU;AAC1B,uBAAiB,CAAC,CAAC;AACnB,mBAAa,KAAK;AAClB,oBAAc,KAAK;AACnB,0BAAoB,IAAI;AACxB,6BAAuB,IAAI;AAC3B,YAAM,QAAQ,mCAAmC;AAAA,IACnD,SAAS,OAAO;AACd,YAAM,MAAM,+BAA+B;AAAA,IAC7C;AAAA,EACF;AAEA,QAAM,eAAe,MAAM;AACzB,qBAAiB,CAAC,CAAC;AACnB,iBAAa,KAAK;AAClB,kBAAc,KAAK;AACnB,wBAAoB,IAAI;AACxB,2BAAuB,IAAI;AAAA,EAC7B;AAEA,QAAM,EAAE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,EAAE,IAAI,oBAAoB;AAEvE,QAAM,UAAU,mBACZ,IAAI,gBAAgB,gBAAgB,KACpC,6CAAc,YAAW,WACvB,GAAG,QAAQ,cAAc,aAAa,OAAO,KAC7C;AAEN,QAAM,aAAa,sBACf,IAAI,gBAAgB,mBAAmB,KACvC,6CAAc,eAAc,WAC1B,GAAG,QAAQ,cAAc,aAAa,UAAU,KAChD;AAQN,MAAI,uBAAuB;AACzB,WACE,oBAAC,wBAAqB;AAAA,EAE1B;AAEA,MAAI,CAAC,cAAc;AACjB,WACE,oBAAC,SAAI,WAAU,2CACb,8BAAC,OAAE,WAAU,yBAAyB,YAAE,yBAAyB,GAAE,GACrE;AAAA,EAEJ;AAEA,QAAM,sBACN,0BACI,OAAO,OAAO,uBAAuB,EAAE,IAAI,CAAC,gBAAqB,YAAY,IAAI,IACjF,CAAC;AAEL,SACE,qBAAC,SAAI,WAAU,wCAEb;AAAA,yBAAC,SAAI,WAAU,wDACb;AAAA,2BAAC,SACC;AAAA,4BAAC,QAAG,WAAU,0BAA0B,YAAE,QAAQ,GAAE;AAAA,QACpD,oBAAC,OAAE,WAAU,iCAAiC,YAAE,WAAW,GAAE;AAAA,SAC/D;AAAA,MACA,oBAAC,SAAI,WAAU,cACZ,sBACC,iCACE;AAAA,4BAAC,UAAO,SAAQ,WAAU,SAAS,cAAc,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc,GAC7F,YAAE,QAAQ,GACb;AAAA,QACA,qBAAC,UAAO,SAAS,YAAY,UAAU,CAAC,cAAc,CAAC,QAAQ,IAAI,UAAU,cAAc,GACzF;AAAA,8BAAC,GAAG,MAAH,EAAQ,WAAU,QAAO;AAAA,UACzB,EAAE,MAAM;AAAA,WACX;AAAA,SACF,IAEA,qBAAC,UAAO,SAAS,MAAM,aAAa,IAAI,GAAG,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc,GACxF;AAAA,4BAAC,GAAG,QAAH,EAAU,WAAU,QAAO;AAAA,QAC3B,EAAE,MAAM;AAAA,SACX,GAEJ;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,4BACb,+BAAC,SAAI,WAAU,+BAEb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,QAAG,WAAU,yBAAyB,YAAE,mBAAmB,GAAE;AAAA,QAC9D,qBAAC,SAAI,WAAU,yCAEb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,aAAa,GAAE;AAAA,YACzD,qBAAC,SAAI,WAAU,2BACb;AAAA,mCAAC,SAAI,WAAU,wGACZ;AAAA,0BACC,oBAAC,SAAI,KAAK,SAAS,KAAI,qBAAoB,WAAU,gCAA+B,IAEpF,oBAAC,GAAG,WAAH,EAAa,WAAU,mCAAkC;AAAA,gBAE3D,aACC,qBAAC,WAAM,WAAU,qIACf;AAAA,sCAAC,GAAG,QAAH,EAAU,WAAU,sBAAqB;AAAA,kBAC1C;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,QAAO;AAAA,sBACP,WAAU;AAAA,sBACV,UAAU,CAAC,MAAM;AAxN3C,4BAAAA;AAyN4B,8BAAM,QAAOA,MAAA,EAAE,OAAO,UAAT,gBAAAA,IAAiB;AAC9B,4BAAI,MAAM;AACR,8CAAoB,IAAI;AACxB,wCAAc,IAAI;AAAA,wBACpB;AAAA,sBACF;AAAA,sBACA,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,kBACjD;AAAA,mBACF;AAAA,iBAEJ;AAAA,cACC,aAAa,WACZ;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,SAAS,MAAM;AACb,wCAAoB,IAAI;AACxB,sCAAkB,WAAW,IAAI;AAAA,kBACnC;AAAA,kBACA,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAChD;AAAA;AAAA,cAED;AAAA,eAEJ;AAAA,aACF;AAAA,UAGA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,gBAAgB,GAAE;AAAA,YAC5D,qBAAC,SAAI,WAAU,2BACb;AAAA,mCAAC,SAAI,WAAU,wGACZ;AAAA,6BACC,oBAAC,SAAI,KAAK,YAAY,KAAI,WAAU,WAAU,gCAA+B,IAE7E,oBAAC,GAAG,OAAH,EAAS,WAAU,iCAAgC;AAAA,gBAErD,aACC,qBAAC,WAAM,WAAU,qIACf;AAAA,sCAAC,GAAG,QAAH,EAAU,WAAU,sBAAqB;AAAA,kBAC1C;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,QAAO;AAAA,sBACP,WAAU;AAAA,sBACV,UAAU,CAAC,MAAM;AArQ3C,4BAAAA;AAsQ4B,8BAAM,QAAOA,MAAA,EAAE,OAAO,UAAT,gBAAAA,IAAiB;AAC9B,4BAAI,MAAM;AACR,iDAAuB,IAAI;AAC3B,wCAAc,IAAI;AAAA,wBACpB;AAAA,sBACF;AAAA,sBACA,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,kBACjD;AAAA,mBACF;AAAA,iBAEJ;AAAA,cACC,aAAa,cACZ;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,SAAS,MAAM;AACb,2CAAuB,IAAI;AAC3B,sCAAkB,cAAc,IAAI;AAAA,kBACtC;AAAA,kBACA,UAAU,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAChD;AAAA;AAAA,cAED;AAAA,eAEJ;AAAA,aACF;AAAA,WACF;AAAA,QAGA,qBAAC,SAAI,WAAU,yCACb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,kBAAkB,GAAE;AAAA,YAC9D,qBAAC,SAAI,WAAU,cACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAQ,cAAc,WAAW,KAAgB;AAAA,kBACjD,UAAU,CAAC,MAAM,kBAAkB,aAAa,EAAE,OAAO,KAAK;AAAA,kBAC9D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAC7D,WAAU;AAAA;AAAA,cAEZ;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAQ,cAAc,WAAW,KAAgB;AAAA,kBACjD,UAAU,CAAC,MAAM,kBAAkB,aAAa,EAAE,OAAO,KAAK;AAAA,kBAC9D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAC7D,aAAY;AAAA;AAAA,cACd;AAAA,eACF;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,uBAAuB,GAAE;AAAA,YACnE,qBAAC,SAAI,WAAU,cACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAQ,cAAc,gBAAgB,KAAgB;AAAA,kBACtD,UAAU,CAAC,MAAM,kBAAkB,kBAAkB,EAAE,OAAO,KAAK;AAAA,kBACnE,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAC7D,WAAU;AAAA;AAAA,cACZ;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAQ,cAAc,gBAAgB,KAAgB;AAAA,kBACtD,UAAU,CAAC,MAAM,kBAAkB,kBAAkB,EAAE,OAAO,KAAK;AAAA,kBACnE,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,kBAC7D,aAAY;AAAA;AAAA,cACd;AAAA,eACF;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,MAEA,oBAAC,aAAU;AAAA,MAGX,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,QAAG,WAAU,yBAAyB,YAAE,oBAAoB,GAAE;AAAA,QAC/D,qBAAC,SAAI,WAAU,yCACb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,aAAa,GAAE;AAAA,YACzD;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,MAAM,KAAgB;AAAA,gBAC5C,UAAU,CAAC,MAAM,kBAAkB,QAAQ,EAAE,OAAO,KAAK;AAAA,gBACzD,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,cAAc,GAAE;AAAA,YAC1D;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,OAAO,KAAgB;AAAA,gBAC7C,UAAU,CAAC,MAAM,kBAAkB,SAAS,EAAE,OAAO,KAAK;AAAA,gBAC1D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAU,aACb;AAAA,8BAAC,WAAM,WAAU,uBAAuB,YAAE,oBAAoB,GAAE;AAAA,UAChE;AAAA,YAAC;AAAA;AAAA,cACC,OAAQ,cAAc,aAAa,KAAgB;AAAA,cACnD,UAAU,CAAC,MAAM,kBAAkB,eAAe,EAAE,OAAO,KAAK;AAAA,cAChE,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA,cAC7D,MAAM;AAAA;AAAA,UACR;AAAA,WACF;AAAA,SACF;AAAA,MAEA,oBAAC,aAAU;AAAA,MAGX,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,QAAG,WAAU,yBAAyB,YAAE,mBAAmB,GAAE;AAAA,QAC9D,qBAAC,SAAI,WAAU,yCACb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,2BAA2B,GAAE;AAAA,YACvE;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO,OAAO,cAAc,oBAAoB,KAAK,EAAE;AAAA,gBACvD,eAAe,CAAC,UAAU,kBAAkB,sBAAsB,KAAK;AAAA,gBACvE,UAAU,CAAC;AAAA,gBAEX;AAAA,sCAAC,iBACC,8BAAC,eAAY,aAAa,EAAE,6BAA6B,GAAG,GAC9D;AAAA,kBACA,oBAAC,iBACE,8BAAoB,IAAI,CAAC,WACxB,oBAAC,cAAwB,OAAO,QAC7B,oBADc,MAEjB,CACD,GACH;AAAA;AAAA;AAAA,YACF;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,qBAAqB,GAAE;AAAA,YACjE;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,cAAc,KAAgB;AAAA,gBACpD,UAAU,CAAC,MAAM,kBAAkB,gBAAgB,EAAE,OAAO,KAAK;AAAA,gBACjE,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,mBAAmB,GAAE;AAAA,YAC/D;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,YAAY,KAAgB;AAAA,gBAClD,UAAU,CAAC,MAAM,kBAAkB,cAAc,EAAE,OAAO,KAAK;AAAA,gBAC/D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,mBAAmB,GAAE;AAAA,YAC/D;AAAA,cAAC;AAAA;AAAA,gBACC,OAAQ,cAAc,YAAY,KAAgB;AAAA,gBAClD,UAAU,CAAC,MAAM,kBAAkB,cAAc,EAAE,OAAO,KAAK;AAAA,gBAC/D,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,MAEA,oBAAC,aAAU;AAAA,MAGX,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,QAAG,WAAU,yBAAyB,YAAE,oBAAoB,GAAE;AAAA,QAC/D,qBAAC,SAAI,WAAU,wDACb;AAAA,+BAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,iBAAiB,GAAE;AAAA,YAC7D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,KAAK,MAAnB,YAAmC;AAAA,gBAC3C,UAAU,CAAC,MAAM,kBAAkB,OAAO,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAC5F,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,kBAAkB,GAAE;AAAA,YAC9D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,MAAM,MAApB,YAAoC;AAAA,gBAC5C,UAAU,CAAC,MAAM,kBAAkB,QAAQ,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAC7F,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,aAAa,GAAE;AAAA,YACzD;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,MAAM,MAApB,YAAoC;AAAA,gBAC5C,UAAU,CAAC,MAAM,kBAAkB,QAAQ,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAC7F,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,gBAAgB,GAAE;AAAA,YAC5D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,SAAS,MAAvB,YAAuC;AAAA,gBAC/C,UAAU,CAAC,MAAM,kBAAkB,WAAW,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAChG,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,gBAAgB,GAAE;AAAA,YAC5D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,SAAS,MAAvB,YAAuC;AAAA,gBAC/C,UAAU,CAAC,MAAM,kBAAkB,WAAW,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAChG,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,WAAM,WAAU,uBAAuB,YAAE,cAAc,GAAE;AAAA,YAC1D;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAQ,mBAAc,OAAO,MAArB,YAAqC;AAAA,gBAC7C,UAAU,CAAC,MAAM,kBAAkB,SAAS,EAAE,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,IAAI,IAAI;AAAA,gBAC9F,UAAU,CAAC,aAAa,CAAC,QAAQ,IAAI,UAAU,cAAc;AAAA;AAAA,YAC/D;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,OACF,GACF;AAAA,KACF;AAEJ;","names":["_a"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnimatedBackground.d.ts","sourceRoot":"","sources":["../../../../src/core/components/ui/AnimatedBackground.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AnimatedBackground.d.ts","sourceRoot":"","sources":["../../../../src/core/components/ui/AnimatedBackground.tsx"],"names":[],"mappings":"AASA,UAAU,KAAK;IACb,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;CACzB;AAED,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,KAAK,EAAE,GAAE,KAAU,+BA8O/D"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import { useMotionValue, useSpring } from "framer-motion";
|
|
5
|
+
import { useAppConfigContext } from "../../store/AppConfig/context";
|
|
5
6
|
function AnimatedBackground({ theme } = {}) {
|
|
6
7
|
const canvasRef = useRef(null);
|
|
7
8
|
const mouseX = useMotionValue(0);
|
|
@@ -156,7 +157,8 @@ function AnimatedBackground({ theme } = {}) {
|
|
|
156
157
|
window.removeEventListener("resize", resize);
|
|
157
158
|
};
|
|
158
159
|
}, [smoothMouseX, smoothMouseY, isDark]);
|
|
159
|
-
const
|
|
160
|
+
const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext();
|
|
161
|
+
const assetsUrl = minioUrl || "";
|
|
160
162
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
161
163
|
/* @__PURE__ */ jsx("div", { className: "absolute top-0 right-0 inset-0 z-10 w-screen", children: /* @__PURE__ */ jsx(
|
|
162
164
|
"img",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/components/ui/AnimatedBackground.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 { useEffect, useRef, useState } from 'react'\r\nimport { useMotionValue, useSpring } from 'framer-motion'\r\n\r\ninterface Props {\r\n theme?: 'light' | 'dark'\r\n}\r\n\r\nexport default function AnimatedBackground({ theme }: Props = {}) {\r\n const canvasRef = useRef<HTMLCanvasElement>(null)\r\n const mouseX = useMotionValue(0)\r\n const mouseY = useMotionValue(0)\r\n const smoothMouseX = useSpring(mouseX, { stiffness: 50, damping: 20 })\r\n const smoothMouseY = useSpring(mouseY, { stiffness: 50, damping: 20 })\r\n const [isDark, setIsDark] = useState(theme !== undefined ? theme === 'dark' : true)\r\n\r\n useEffect(() => {\r\n // If theme is controlled externally, just sync and skip the observer\r\n if (theme !== undefined) {\r\n setIsDark(theme === 'dark')\r\n return\r\n }\r\n\r\n // Auto-detect from document for standalone usage (hero section)\r\n setIsDark(document.documentElement.classList.contains('dark'))\r\n const observer = new MutationObserver(() => {\r\n setIsDark(document.documentElement.classList.contains('dark'))\r\n })\r\n observer.observe(document.documentElement, {\r\n attributes: true,\r\n attributeFilter: ['class']\r\n })\r\n return () => observer.disconnect()\r\n }, [theme])\r\n\r\n useEffect(() => {\r\n const handleMouseMove = (e: MouseEvent) => {\r\n mouseX.set(e.clientX)\r\n mouseY.set(e.clientY)\r\n }\r\n\r\n window.addEventListener('mousemove', handleMouseMove)\r\n return () => window.removeEventListener('mousemove', handleMouseMove)\r\n }, [mouseX, mouseY])\r\n\r\n useEffect(() => {\r\n const canvas = canvasRef.current\r\n if (!canvas) return\r\n\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) return\r\n\r\n const resize = () => {\r\n canvas.width = window.innerWidth\r\n canvas.height = window.innerHeight\r\n }\r\n resize()\r\n window.addEventListener('resize', resize)\r\n\r\n let animationFrameId: number\r\n let time = 0\r\n let offsetX = 0\r\n\r\n interface DataNode {\r\n x: number\r\n y: number\r\n baseX: number\r\n baseY: number\r\n connections: number[]\r\n pulse: number\r\n }\r\n\r\n const dataNodes: DataNode[] = []\r\n const gridSize = 100\r\n const nodeSpacing = 150\r\n // Render extra columns for seamless wrap\r\n const nodeCols = Math.ceil(canvas.width / nodeSpacing) + 2\r\n const nodeRows = Math.ceil(canvas.height / nodeSpacing)\r\n\r\n for (let row = 0; row < nodeRows; row++) {\r\n for (let col = 0; col < nodeCols; col++) {\r\n const index = row * nodeCols + col\r\n const baseX = col * nodeSpacing + nodeSpacing / 2\r\n const baseY = row * nodeSpacing + nodeSpacing / 2\r\n dataNodes.push({\r\n x: baseX,\r\n y: baseY,\r\n baseX,\r\n baseY,\r\n connections: [],\r\n pulse: (row + col) * 0.5\r\n })\r\n }\r\n }\r\n\r\n dataNodes.forEach((node, i) => {\r\n const col = i % nodeCols\r\n const row = Math.floor(i / nodeCols)\r\n if (col < nodeCols - 1) {\r\n node.connections.push(i + 1)\r\n }\r\n if (row < nodeRows - 1) {\r\n node.connections.push(i + nodeCols)\r\n }\r\n })\r\n\r\n const draw = () => {\r\n time += 0.008\r\n // Move left slowly\r\n offsetX += 0.1 // Lower for slower movement\r\n // Loop offsetX to avoid overflow and create infinite effect\r\n if (offsetX > nodeSpacing) offsetX -= nodeSpacing\r\n\r\n ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Theme-aware colors\r\n const bgGradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height)\r\n if (isDark) {\r\n bgGradient.addColorStop(0, 'rgba(239, 145, 97, 0.025)')\r\n bgGradient.addColorStop(1, 'rgba(180, 90, 40, 0.02)')\r\n } else {\r\n bgGradient.addColorStop(0, 'rgba(239, 146, 98, 0.08)')\r\n bgGradient.addColorStop(1, 'rgba(239, 146, 98, 0.06)')\r\n }\r\n ctx.fillStyle = bgGradient\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Animate node positions with floating effect\r\n dataNodes.forEach((node, i) => {\r\n const floatX = Math.sin(time * 0.3 + node.pulse) * 2\r\n const floatY = Math.cos(time * 0.2 + node.pulse) * 2\r\n // Shift node baseX by offsetX for infinite left movement\r\n let x = node.baseX - offsetX + floatX\r\n // Wrap node.x to the right if it goes off the left edge\r\n x = ((x + nodeCols * nodeSpacing) % (nodeCols * nodeSpacing))\r\n node.x = x\r\n node.y = node.baseY + floatY\r\n })\r\n\r\n // Theme-aware grid lines\r\n ctx.strokeStyle = isDark ? 'rgba(239, 145, 97, 0.08)' : 'rgba(239, 146, 98, 0.3)'\r\n ctx.lineWidth = 0.5\r\n \r\n for (let y = canvas.height; y > canvas.height * 0.3; y -= gridSize) {\r\n ctx.beginPath()\r\n ctx.moveTo(0, y)\r\n ctx.lineTo(canvas.width, y)\r\n ctx.stroke()\r\n }\r\n \r\n const verticalSpacing = gridSize * 1.5\r\n // Render extra vertical grid lines for seamless wrap\r\n const gridCols = Math.ceil(canvas.width / verticalSpacing) + 2\r\n for (let i = 0; i < gridCols; i++) {\r\n // Shift grid lines by offsetX for infinite left movement\r\n let x = i * verticalSpacing - offsetX % verticalSpacing - verticalSpacing\r\n // Wrap x for seamless effect\r\n x = ((x + gridCols * verticalSpacing) % (gridCols * verticalSpacing))\r\n ctx.beginPath()\r\n ctx.moveTo(x, canvas.height)\r\n ctx.lineTo(x + (x - canvas.width / 2) * 0.3, canvas.height * 0.3)\r\n ctx.stroke()\r\n }\r\n\r\n // Theme-aware connections with data flow\r\n ctx.lineWidth = 0.8\r\n dataNodes.forEach((node, i) => {\r\n node.connections.forEach(targetIndex => {\r\n const target = dataNodes[targetIndex]\r\n const pulse = (Math.sin(time + node.pulse) + 1) / 2\r\n \r\n ctx.beginPath()\r\n ctx.moveTo(node.x, node.y)\r\n ctx.lineTo(target.x, target.y)\r\n ctx.strokeStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.1 + pulse * 0.08})`\r\n : `rgba(239, 146, 98, ${0.35 + pulse * 0.2})`\r\n ctx.stroke()\r\n\r\n // Animated data particles flowing along connections\r\n const flowProgress = (time * 0.3 + node.pulse) % 1\r\n const particleX = node.x + (target.x - node.x) * flowProgress\r\n const particleY = node.y + (target.y - node.y) * flowProgress\r\n\r\n ctx.beginPath()\r\n ctx.arc(particleX, particleY, 1.5, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.5 + pulse * 0.3})`\r\n : `rgba(239, 146, 98, ${0.7 + pulse * 0.3})`\r\n ctx.fill()\r\n })\r\n })\r\n\r\n // Theme-aware nodes\r\n dataNodes.forEach(node => {\r\n const pulse = (Math.sin(time + node.pulse) + 1) / 2\r\n const size = 2.5 + pulse * 1\r\n \r\n ctx.beginPath()\r\n ctx.arc(node.x, node.y, size * 2, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.12 + pulse * 0.1})`\r\n : `rgba(239, 146, 98, ${0.3 + pulse * 0.15})`\r\n ctx.fill()\r\n\r\n ctx.beginPath()\r\n ctx.arc(node.x, node.y, size, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.55 + pulse * 0.25})`\r\n : `rgba(239, 146, 98, ${0.75 + pulse * 0.2})`\r\n ctx.fill()\r\n })\r\n\r\n animationFrameId = requestAnimationFrame(draw)\r\n }\r\n\r\n draw()\r\n\r\n return () => {\r\n cancelAnimationFrame(animationFrameId)\r\n window.removeEventListener('resize', resize)\r\n }\r\n }, [smoothMouseX, smoothMouseY, isDark])\r\n\r\n const assetsUrl = process.env.NEXT_PUBLIC_MINIO_BUCKET_URL || ''\r\n\r\n return (\r\n <>\r\n <div className=\"absolute top-0 right-0 inset-0 z-10 w-screen\">\r\n <img\r\n src={`${assetsUrl}/cdt-homepage/home-bg.png`}\r\n alt=\"Background\"\r\n className=\"object-cover opacity-10 w-screen\"\r\n style={{ filter: isDark ? 'invert(0)' : 'invert(1)' }}\r\n />\r\n </div>\r\n <div className=\"absolute w-screen inset-0 bg-gradient-to-br from-background/10 via-background/5 to-primary/5\" />\r\n <canvas\r\n ref={canvasRef}\r\n className=\"absolute inset-0 w-full h-full opacity-30\"\r\n style={{ mixBlendMode: isDark ? 'screen' : 'multiply' }}\r\n />\r\n <div className=\"absolute inset-0 bg-gradient-to-t from-background/30 via-background/10 to-transparent\" />\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/components/ui/AnimatedBackground.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 { useEffect, useRef, useState } from 'react'\r\nimport { useMotionValue, useSpring } from 'framer-motion'\r\nimport { useAppConfigContext } from '../../store/AppConfig/context'\r\n\r\ninterface Props {\r\n theme?: 'light' | 'dark'\r\n}\r\n\r\nexport default function AnimatedBackground({ theme }: Props = {}) {\r\n const canvasRef = useRef<HTMLCanvasElement>(null)\r\n const mouseX = useMotionValue(0)\r\n const mouseY = useMotionValue(0)\r\n const smoothMouseX = useSpring(mouseX, { stiffness: 50, damping: 20 })\r\n const smoothMouseY = useSpring(mouseY, { stiffness: 50, damping: 20 })\r\n const [isDark, setIsDark] = useState(theme !== undefined ? theme === 'dark' : true)\r\n\r\n useEffect(() => {\r\n // If theme is controlled externally, just sync and skip the observer\r\n if (theme !== undefined) {\r\n setIsDark(theme === 'dark')\r\n return\r\n }\r\n\r\n // Auto-detect from document for standalone usage (hero section)\r\n setIsDark(document.documentElement.classList.contains('dark'))\r\n const observer = new MutationObserver(() => {\r\n setIsDark(document.documentElement.classList.contains('dark'))\r\n })\r\n observer.observe(document.documentElement, {\r\n attributes: true,\r\n attributeFilter: ['class']\r\n })\r\n return () => observer.disconnect()\r\n }, [theme])\r\n\r\n useEffect(() => {\r\n const handleMouseMove = (e: MouseEvent) => {\r\n mouseX.set(e.clientX)\r\n mouseY.set(e.clientY)\r\n }\r\n\r\n window.addEventListener('mousemove', handleMouseMove)\r\n return () => window.removeEventListener('mousemove', handleMouseMove)\r\n }, [mouseX, mouseY])\r\n\r\n useEffect(() => {\r\n const canvas = canvasRef.current\r\n if (!canvas) return\r\n\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) return\r\n\r\n const resize = () => {\r\n canvas.width = window.innerWidth\r\n canvas.height = window.innerHeight\r\n }\r\n resize()\r\n window.addEventListener('resize', resize)\r\n\r\n let animationFrameId: number\r\n let time = 0\r\n let offsetX = 0\r\n\r\n interface DataNode {\r\n x: number\r\n y: number\r\n baseX: number\r\n baseY: number\r\n connections: number[]\r\n pulse: number\r\n }\r\n\r\n const dataNodes: DataNode[] = []\r\n const gridSize = 100\r\n const nodeSpacing = 150\r\n // Render extra columns for seamless wrap\r\n const nodeCols = Math.ceil(canvas.width / nodeSpacing) + 2\r\n const nodeRows = Math.ceil(canvas.height / nodeSpacing)\r\n\r\n for (let row = 0; row < nodeRows; row++) {\r\n for (let col = 0; col < nodeCols; col++) {\r\n const index = row * nodeCols + col\r\n const baseX = col * nodeSpacing + nodeSpacing / 2\r\n const baseY = row * nodeSpacing + nodeSpacing / 2\r\n dataNodes.push({\r\n x: baseX,\r\n y: baseY,\r\n baseX,\r\n baseY,\r\n connections: [],\r\n pulse: (row + col) * 0.5\r\n })\r\n }\r\n }\r\n\r\n dataNodes.forEach((node, i) => {\r\n const col = i % nodeCols\r\n const row = Math.floor(i / nodeCols)\r\n if (col < nodeCols - 1) {\r\n node.connections.push(i + 1)\r\n }\r\n if (row < nodeRows - 1) {\r\n node.connections.push(i + nodeCols)\r\n }\r\n })\r\n\r\n const draw = () => {\r\n time += 0.008\r\n // Move left slowly\r\n offsetX += 0.1 // Lower for slower movement\r\n // Loop offsetX to avoid overflow and create infinite effect\r\n if (offsetX > nodeSpacing) offsetX -= nodeSpacing\r\n\r\n ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Theme-aware colors\r\n const bgGradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height)\r\n if (isDark) {\r\n bgGradient.addColorStop(0, 'rgba(239, 145, 97, 0.025)')\r\n bgGradient.addColorStop(1, 'rgba(180, 90, 40, 0.02)')\r\n } else {\r\n bgGradient.addColorStop(0, 'rgba(239, 146, 98, 0.08)')\r\n bgGradient.addColorStop(1, 'rgba(239, 146, 98, 0.06)')\r\n }\r\n ctx.fillStyle = bgGradient\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Animate node positions with floating effect\r\n dataNodes.forEach((node, i) => {\r\n const floatX = Math.sin(time * 0.3 + node.pulse) * 2\r\n const floatY = Math.cos(time * 0.2 + node.pulse) * 2\r\n // Shift node baseX by offsetX for infinite left movement\r\n let x = node.baseX - offsetX + floatX\r\n // Wrap node.x to the right if it goes off the left edge\r\n x = ((x + nodeCols * nodeSpacing) % (nodeCols * nodeSpacing))\r\n node.x = x\r\n node.y = node.baseY + floatY\r\n })\r\n\r\n // Theme-aware grid lines\r\n ctx.strokeStyle = isDark ? 'rgba(239, 145, 97, 0.08)' : 'rgba(239, 146, 98, 0.3)'\r\n ctx.lineWidth = 0.5\r\n \r\n for (let y = canvas.height; y > canvas.height * 0.3; y -= gridSize) {\r\n ctx.beginPath()\r\n ctx.moveTo(0, y)\r\n ctx.lineTo(canvas.width, y)\r\n ctx.stroke()\r\n }\r\n \r\n const verticalSpacing = gridSize * 1.5\r\n // Render extra vertical grid lines for seamless wrap\r\n const gridCols = Math.ceil(canvas.width / verticalSpacing) + 2\r\n for (let i = 0; i < gridCols; i++) {\r\n // Shift grid lines by offsetX for infinite left movement\r\n let x = i * verticalSpacing - offsetX % verticalSpacing - verticalSpacing\r\n // Wrap x for seamless effect\r\n x = ((x + gridCols * verticalSpacing) % (gridCols * verticalSpacing))\r\n ctx.beginPath()\r\n ctx.moveTo(x, canvas.height)\r\n ctx.lineTo(x + (x - canvas.width / 2) * 0.3, canvas.height * 0.3)\r\n ctx.stroke()\r\n }\r\n\r\n // Theme-aware connections with data flow\r\n ctx.lineWidth = 0.8\r\n dataNodes.forEach((node, i) => {\r\n node.connections.forEach(targetIndex => {\r\n const target = dataNodes[targetIndex]\r\n const pulse = (Math.sin(time + node.pulse) + 1) / 2\r\n \r\n ctx.beginPath()\r\n ctx.moveTo(node.x, node.y)\r\n ctx.lineTo(target.x, target.y)\r\n ctx.strokeStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.1 + pulse * 0.08})`\r\n : `rgba(239, 146, 98, ${0.35 + pulse * 0.2})`\r\n ctx.stroke()\r\n\r\n // Animated data particles flowing along connections\r\n const flowProgress = (time * 0.3 + node.pulse) % 1\r\n const particleX = node.x + (target.x - node.x) * flowProgress\r\n const particleY = node.y + (target.y - node.y) * flowProgress\r\n\r\n ctx.beginPath()\r\n ctx.arc(particleX, particleY, 1.5, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.5 + pulse * 0.3})`\r\n : `rgba(239, 146, 98, ${0.7 + pulse * 0.3})`\r\n ctx.fill()\r\n })\r\n })\r\n\r\n // Theme-aware nodes\r\n dataNodes.forEach(node => {\r\n const pulse = (Math.sin(time + node.pulse) + 1) / 2\r\n const size = 2.5 + pulse * 1\r\n \r\n ctx.beginPath()\r\n ctx.arc(node.x, node.y, size * 2, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.12 + pulse * 0.1})`\r\n : `rgba(239, 146, 98, ${0.3 + pulse * 0.15})`\r\n ctx.fill()\r\n\r\n ctx.beginPath()\r\n ctx.arc(node.x, node.y, size, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.55 + pulse * 0.25})`\r\n : `rgba(239, 146, 98, ${0.75 + pulse * 0.2})`\r\n ctx.fill()\r\n })\r\n\r\n animationFrameId = requestAnimationFrame(draw)\r\n }\r\n\r\n draw()\r\n\r\n return () => {\r\n cancelAnimationFrame(animationFrameId)\r\n window.removeEventListener('resize', resize)\r\n }\r\n }, [smoothMouseX, smoothMouseY, isDark])\r\n\r\n const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext()\r\n const assetsUrl = minioUrl || ''\r\n\r\n return (\r\n <>\r\n <div className=\"absolute top-0 right-0 inset-0 z-10 w-screen\">\r\n <img\r\n src={`${assetsUrl}/cdt-homepage/home-bg.png`}\r\n alt=\"Background\"\r\n className=\"object-cover opacity-10 w-screen\"\r\n style={{ filter: isDark ? 'invert(0)' : 'invert(1)' }}\r\n />\r\n </div>\r\n <div className=\"absolute w-screen inset-0 bg-gradient-to-br from-background/10 via-background/5 to-primary/5\" />\r\n <canvas\r\n ref={canvasRef}\r\n className=\"absolute inset-0 w-full h-full opacity-30\"\r\n style={{ mixBlendMode: isDark ? 'screen' : 'multiply' }}\r\n />\r\n <div className=\"absolute inset-0 bg-gradient-to-t from-background/30 via-background/10 to-transparent\" />\r\n </>\r\n )\r\n}\r\n"],"mappings":";AAyOI,mBAEI,KAFJ;AApOJ,SAAS,WAAW,QAAQ,gBAAgB;AAC5C,SAAS,gBAAgB,iBAAiB;AAC1C,SAAS,2BAA2B;AAMrB,SAAR,mBAAoC,EAAE,MAAM,IAAW,CAAC,GAAG;AAChE,QAAM,YAAY,OAA0B,IAAI;AAChD,QAAM,SAAS,eAAe,CAAC;AAC/B,QAAM,SAAS,eAAe,CAAC;AAC/B,QAAM,eAAe,UAAU,QAAQ,EAAE,WAAW,IAAI,SAAS,GAAG,CAAC;AACrE,QAAM,eAAe,UAAU,QAAQ,EAAE,WAAW,IAAI,SAAS,GAAG,CAAC;AACrE,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,UAAU,SAAY,UAAU,SAAS,IAAI;AAElF,YAAU,MAAM;AAEd,QAAI,UAAU,QAAW;AACvB,gBAAU,UAAU,MAAM;AAC1B;AAAA,IACF;AAGA,cAAU,SAAS,gBAAgB,UAAU,SAAS,MAAM,CAAC;AAC7D,UAAM,WAAW,IAAI,iBAAiB,MAAM;AAC1C,gBAAU,SAAS,gBAAgB,UAAU,SAAS,MAAM,CAAC;AAAA,IAC/D,CAAC;AACD,aAAS,QAAQ,SAAS,iBAAiB;AAAA,MACzC,YAAY;AAAA,MACZ,iBAAiB,CAAC,OAAO;AAAA,IAC3B,CAAC;AACD,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACd,UAAM,kBAAkB,CAAC,MAAkB;AACzC,aAAO,IAAI,EAAE,OAAO;AACpB,aAAO,IAAI,EAAE,OAAO;AAAA,IACtB;AAEA,WAAO,iBAAiB,aAAa,eAAe;AACpD,WAAO,MAAM,OAAO,oBAAoB,aAAa,eAAe;AAAA,EACtE,GAAG,CAAC,QAAQ,MAAM,CAAC;AAEnB,YAAU,MAAM;AACd,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AAEb,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,CAAC,IAAK;AAEV,UAAM,SAAS,MAAM;AACnB,aAAO,QAAQ,OAAO;AACtB,aAAO,SAAS,OAAO;AAAA,IACzB;AACA,WAAO;AACP,WAAO,iBAAiB,UAAU,MAAM;AAExC,QAAI;AACJ,QAAI,OAAO;AACX,QAAI,UAAU;AAWd,UAAM,YAAwB,CAAC;AAC/B,UAAM,WAAW;AACjB,UAAM,cAAc;AAEpB,UAAM,WAAW,KAAK,KAAK,OAAO,QAAQ,WAAW,IAAI;AACzD,UAAM,WAAW,KAAK,KAAK,OAAO,SAAS,WAAW;AAEtD,aAAS,MAAM,GAAG,MAAM,UAAU,OAAO;AACvC,eAAS,MAAM,GAAG,MAAM,UAAU,OAAO;AACvC,cAAM,QAAQ,MAAM,WAAW;AAC/B,cAAM,QAAQ,MAAM,cAAc,cAAc;AAChD,cAAM,QAAQ,MAAM,cAAc,cAAc;AAChD,kBAAU,KAAK;AAAA,UACb,GAAG;AAAA,UACH,GAAG;AAAA,UACH;AAAA,UACA;AAAA,UACA,aAAa,CAAC;AAAA,UACd,QAAQ,MAAM,OAAO;AAAA,QACvB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,cAAU,QAAQ,CAAC,MAAM,MAAM;AAC7B,YAAM,MAAM,IAAI;AAChB,YAAM,MAAM,KAAK,MAAM,IAAI,QAAQ;AACnC,UAAI,MAAM,WAAW,GAAG;AACtB,aAAK,YAAY,KAAK,IAAI,CAAC;AAAA,MAC7B;AACA,UAAI,MAAM,WAAW,GAAG;AACtB,aAAK,YAAY,KAAK,IAAI,QAAQ;AAAA,MACpC;AAAA,IACF,CAAC;AAED,UAAM,OAAO,MAAM;AACjB,cAAQ;AAER,iBAAW;AAEX,UAAI,UAAU,YAAa,YAAW;AAEtC,UAAI,UAAU,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAG/C,YAAM,aAAa,IAAI,qBAAqB,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAC7E,UAAI,QAAQ;AACV,mBAAW,aAAa,GAAG,2BAA2B;AACtD,mBAAW,aAAa,GAAG,yBAAyB;AAAA,MACtD,OAAO;AACL,mBAAW,aAAa,GAAG,0BAA0B;AACrD,mBAAW,aAAa,GAAG,0BAA0B;AAAA,MACvD;AACA,UAAI,YAAY;AAChB,UAAI,SAAS,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAG9C,gBAAU,QAAQ,CAAC,MAAM,MAAM;AAC7B,cAAM,SAAS,KAAK,IAAI,OAAO,MAAM,KAAK,KAAK,IAAI;AACnD,cAAM,SAAS,KAAK,IAAI,OAAO,MAAM,KAAK,KAAK,IAAI;AAEnD,YAAI,IAAI,KAAK,QAAQ,UAAU;AAE/B,aAAM,IAAI,WAAW,gBAAgB,WAAW;AAChD,aAAK,IAAI;AACT,aAAK,IAAI,KAAK,QAAQ;AAAA,MACxB,CAAC;AAGD,UAAI,cAAc,SAAS,6BAA6B;AACxD,UAAI,YAAY;AAEhB,eAAS,IAAI,OAAO,QAAQ,IAAI,OAAO,SAAS,KAAK,KAAK,UAAU;AAClE,YAAI,UAAU;AACd,YAAI,OAAO,GAAG,CAAC;AACf,YAAI,OAAO,OAAO,OAAO,CAAC;AAC1B,YAAI,OAAO;AAAA,MACb;AAEA,YAAM,kBAAkB,WAAW;AAEnC,YAAM,WAAW,KAAK,KAAK,OAAO,QAAQ,eAAe,IAAI;AAC7D,eAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AAEjC,YAAI,IAAI,IAAI,kBAAkB,UAAU,kBAAkB;AAE1D,aAAM,IAAI,WAAW,oBAAoB,WAAW;AACpD,YAAI,UAAU;AACd,YAAI,OAAO,GAAG,OAAO,MAAM;AAC3B,YAAI,OAAO,KAAK,IAAI,OAAO,QAAQ,KAAK,KAAK,OAAO,SAAS,GAAG;AAChE,YAAI,OAAO;AAAA,MACb;AAGA,UAAI,YAAY;AAChB,gBAAU,QAAQ,CAAC,MAAM,MAAM;AAC7B,aAAK,YAAY,QAAQ,iBAAe;AACtC,gBAAM,SAAS,UAAU,WAAW;AACpC,gBAAM,SAAS,KAAK,IAAI,OAAO,KAAK,KAAK,IAAI,KAAK;AAElD,cAAI,UAAU;AACd,cAAI,OAAO,KAAK,GAAG,KAAK,CAAC;AACzB,cAAI,OAAO,OAAO,GAAG,OAAO,CAAC;AAC7B,cAAI,cAAc,SACd,sBAAsB,MAAM,QAAQ,IAAI,MACxC,sBAAsB,OAAO,QAAQ,GAAG;AAC5C,cAAI,OAAO;AAGX,gBAAM,gBAAgB,OAAO,MAAM,KAAK,SAAS;AACjD,gBAAM,YAAY,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK;AACjD,gBAAM,YAAY,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK;AAEjD,cAAI,UAAU;AACd,cAAI,IAAI,WAAW,WAAW,KAAK,GAAG,KAAK,KAAK,CAAC;AACjD,cAAI,YAAY,SACZ,sBAAsB,MAAM,QAAQ,GAAG,MACvC,sBAAsB,MAAM,QAAQ,GAAG;AAC3C,cAAI,KAAK;AAAA,QACX,CAAC;AAAA,MACH,CAAC;AAGD,gBAAU,QAAQ,UAAQ;AACxB,cAAM,SAAS,KAAK,IAAI,OAAO,KAAK,KAAK,IAAI,KAAK;AAClD,cAAM,OAAO,MAAM,QAAQ;AAE3B,YAAI,UAAU;AACd,YAAI,IAAI,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,GAAG,KAAK,KAAK,CAAC;AAChD,YAAI,YAAY,SACZ,sBAAsB,OAAO,QAAQ,GAAG,MACxC,sBAAsB,MAAM,QAAQ,IAAI;AAC5C,YAAI,KAAK;AAET,YAAI,UAAU;AACd,YAAI,IAAI,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,KAAK,CAAC;AAC5C,YAAI,YAAY,SACZ,sBAAsB,OAAO,QAAQ,IAAI,MACzC,sBAAsB,OAAO,QAAQ,GAAG;AAC5C,YAAI,KAAK;AAAA,MACX,CAAC;AAED,yBAAmB,sBAAsB,IAAI;AAAA,IAC/C;AAEA,SAAK;AAEL,WAAO,MAAM;AACX,2BAAqB,gBAAgB;AACrC,aAAO,oBAAoB,UAAU,MAAM;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,cAAc,cAAc,MAAM,CAAC;AAEvC,QAAM,EAAE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,EAAE,IAAI,oBAAoB;AACvE,QAAM,YAAY,YAAY;AAE9B,SACE,iCACE;AAAA,wBAAC,SAAI,WAAU,gDACb;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,GAAG,SAAS;AAAA,QACjB,KAAI;AAAA,QACJ,WAAU;AAAA,QACV,OAAO,EAAE,QAAQ,SAAS,cAAc,YAAY;AAAA;AAAA,IACtD,GACF;AAAA,IACA,oBAAC,SAAI,WAAU,gGAA+F;AAAA,IAC9G;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,WAAU;AAAA,QACV,OAAO,EAAE,cAAc,SAAS,WAAW,WAAW;AAAA;AAAA,IACxD;AAAA,IACA,oBAAC,SAAI,WAAU,yFAAwF;AAAA,KACzG;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppSidebar.d.ts","sourceRoot":"","sources":["../../../../src/core/components/ui/AppSidebar.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAY9B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGzC,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,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAClF;AAED,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"AppSidebar.d.ts","sourceRoot":"","sources":["../../../../src/core/components/ui/AppSidebar.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAY9B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGzC,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,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAClF;AAED,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,eAAe,qBAmFhE"}
|
|
@@ -50,30 +50,30 @@ function AppSidebar({ children, signOut }) {
|
|
|
50
50
|
/* @__PURE__ */ jsxs(
|
|
51
51
|
"div",
|
|
52
52
|
{
|
|
53
|
-
className: `w-full flex flex-col ${sidebarState === "expanded" ? "items-center justify-center" : "justify-center"}`,
|
|
53
|
+
className: `w-full flex flex-col ${sidebarState === "expanded" ? "items-center justify-center" : "justify-center pb-4"}`,
|
|
54
54
|
children: [
|
|
55
55
|
/* @__PURE__ */ jsx(NavUser, { signOut }),
|
|
56
|
-
/* @__PURE__ */ jsx(
|
|
56
|
+
!isCollapsed ? /* @__PURE__ */ jsx(
|
|
57
57
|
Link,
|
|
58
58
|
{
|
|
59
59
|
href: "https://collabdt.org/",
|
|
60
|
-
className: sidebarState === "expanded" ? "w-full" : "",
|
|
61
60
|
target: "_blank",
|
|
62
61
|
rel: "noopener noreferrer",
|
|
63
|
-
|
|
62
|
+
className: "w-full",
|
|
63
|
+
children: /* @__PURE__ */ jsxs(
|
|
64
64
|
Button,
|
|
65
65
|
{
|
|
66
|
-
title:
|
|
66
|
+
title: t("home"),
|
|
67
67
|
variant: "ghost",
|
|
68
|
-
className:
|
|
69
|
-
children:
|
|
70
|
-
/* @__PURE__ */ jsx(
|
|
71
|
-
|
|
72
|
-
]
|
|
68
|
+
className: "text-xs scale-[85%] py-0 my-0 w-full flex flex-row items-center justify-center gap-2",
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ jsx(CdtIcon, { monochromatic: true }),
|
|
71
|
+
/* @__PURE__ */ jsx("span", { children: t("home") })
|
|
72
|
+
]
|
|
73
73
|
}
|
|
74
74
|
)
|
|
75
75
|
}
|
|
76
|
-
)
|
|
76
|
+
) : null
|
|
77
77
|
]
|
|
78
78
|
}
|
|
79
79
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/components/ui/AppSidebar.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\n\r\n// Dependencies\r\nimport { Button } from './Button'\r\n\r\n// Icons\r\nimport * as LR from 'lucide-react'\r\n\r\nimport { useTranslations } from 'next-intl'\r\nimport { CdtIcon } from './Icons/CdtIcon'\r\nimport Link from 'next/link'\r\nimport { Sidebar, useSidebar, NavUser } from './'\r\nimport { ViewerNames } from '../../types'\r\nimport { useMenusContext } from '../../store'\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 children?: React.ReactNode\r\n signOut: (options?: { redirectTo?: string; redirect?: boolean }) => Promise<void>\r\n}\r\n\r\nexport function AppSidebar({ children, signOut }: AppSidebarProps) {\r\n // Translations\r\n const t = useTranslations('AppSidebar')\r\n\r\n const { state: menusState } = useMenusContext()\r\n\r\n const { sidebarState, isMobile, openMobile, toggleMenuSidebar } = useSidebar()\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 // Determine the collapsible type based on the current viewer\r\n const collapsibleType = currentViewer === ViewerNames.auth ? 'offcanvas' : 'icon'\r\n\r\n return (\r\n <>\r\n {/* Always show toggle button on mobile when collapsed */}\r\n {isMobile && isCollapsed && (\r\n <div id='sidebar-toggle-button-mobile' className='fixed left-0 top-1/2 -translate-y-1/2 z-[100] flex items-center justify-center pointer-events-auto'>\r\n <button\r\n onClick={toggleMenuSidebar}\r\n className=\"text-muted-foreground hover:text-primary p-[2px] rounded-r-md bg-sidebar\"\r\n style={{ border: '1px solid rgba(128,128,128,0.2)', borderLeft: 'none', boxShadow: '4px 0 8px -4px rgba(0,0,0,0.12)' }}\r\n >\r\n <LR.ChevronRight className=\"w-5\" />\r\n </button>\r\n </div>\r\n )}\r\n <Sidebar collapsible={collapsibleType} className=\"border-none z-50 shadow-md relative\" >\r\n {/* Sidebar toggle button - right side inside Sidebar */}\r\n {(sidebarState === 'expanded') && (\r\n <div id='sidebar-toggle-button' className={`absolute right-2 top-2 flex items-center justify-center pointer-events-auto z-50 ${isMobile ? '' : ''}`}>\r\n <button onClick={toggleMenuSidebar} className='text-muted-foreground hover:text-primary p-1'>\r\n <LR.X className='w-5' />\r\n </button>\r\n </div>\r\n )}\r\n {/* Show collapsed toggle only on desktop */}\r\n {!isMobile && sidebarState !== 'expanded' && (\r\n <div id='sidebar-toggle-button' className='absolute -right-1 max-h-1 top-1/2 -translate-y-1/2 flex items-center justify-center pointer-events-auto z-50'>\r\n <button\r\n onClick={toggleMenuSidebar}\r\n className=\"text-muted-foreground hover:text-primary p-0 rounded-md bg-sidebar\"\r\n style={{ borderRight: '1px solid rgba(128,128,128,0.2)', boxShadow: '4px 0 8px -4px rgba(0,0,0,0.12)' }}\r\n >\r\n <LR.ChevronRight className=\"w-4\" />\r\n </button>\r\n </div>\r\n )}\r\n {children}\r\n <div\r\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/components/ui/AppSidebar.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\n\r\n// Dependencies\r\nimport { Button } from './Button'\r\n\r\n// Icons\r\nimport * as LR from 'lucide-react'\r\n\r\nimport { useTranslations } from 'next-intl'\r\nimport { CdtIcon } from './Icons/CdtIcon'\r\nimport Link from 'next/link'\r\nimport { Sidebar, useSidebar, NavUser } from './'\r\nimport { ViewerNames } from '../../types'\r\nimport { useMenusContext } from '../../store'\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 children?: React.ReactNode\r\n signOut: (options?: { redirectTo?: string; redirect?: boolean }) => Promise<void>\r\n}\r\n\r\nexport function AppSidebar({ children, signOut }: AppSidebarProps) {\r\n // Translations\r\n const t = useTranslations('AppSidebar')\r\n\r\n const { state: menusState } = useMenusContext()\r\n\r\n const { sidebarState, isMobile, openMobile, toggleMenuSidebar } = useSidebar()\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 // Determine the collapsible type based on the current viewer\r\n const collapsibleType = currentViewer === ViewerNames.auth ? 'offcanvas' : 'icon'\r\n\r\n return (\r\n <>\r\n {/* Always show toggle button on mobile when collapsed */}\r\n {isMobile && isCollapsed && (\r\n <div id='sidebar-toggle-button-mobile' className='fixed left-0 top-1/2 -translate-y-1/2 z-[100] flex items-center justify-center pointer-events-auto'>\r\n <button\r\n onClick={toggleMenuSidebar}\r\n className=\"text-muted-foreground hover:text-primary p-[2px] rounded-r-md bg-sidebar\"\r\n style={{ border: '1px solid rgba(128,128,128,0.2)', borderLeft: 'none', boxShadow: '4px 0 8px -4px rgba(0,0,0,0.12)' }}\r\n >\r\n <LR.ChevronRight className=\"w-5\" />\r\n </button>\r\n </div>\r\n )}\r\n <Sidebar collapsible={collapsibleType} className=\"border-none z-50 shadow-md relative\" >\r\n {/* Sidebar toggle button - right side inside Sidebar */}\r\n {(sidebarState === 'expanded') && (\r\n <div id='sidebar-toggle-button' className={`absolute right-2 top-2 flex items-center justify-center pointer-events-auto z-50 ${isMobile ? '' : ''}`}>\r\n <button onClick={toggleMenuSidebar} className='text-muted-foreground hover:text-primary p-1'>\r\n <LR.X className='w-5' />\r\n </button>\r\n </div>\r\n )}\r\n {/* Show collapsed toggle only on desktop */}\r\n {!isMobile && sidebarState !== 'expanded' && (\r\n <div id='sidebar-toggle-button' className='absolute -right-1 max-h-1 top-1/2 -translate-y-1/2 flex items-center justify-center pointer-events-auto z-50'>\r\n <button\r\n onClick={toggleMenuSidebar}\r\n className=\"text-muted-foreground hover:text-primary p-0 rounded-md bg-sidebar\"\r\n style={{ borderRight: '1px solid rgba(128,128,128,0.2)', boxShadow: '4px 0 8px -4px rgba(0,0,0,0.12)' }}\r\n >\r\n <LR.ChevronRight className=\"w-4\" />\r\n </button>\r\n </div>\r\n )}\r\n {children}\r\n <div\r\n className={`w-full flex flex-col ${\r\n sidebarState === 'expanded'\r\n ? 'items-center justify-center'\r\n : 'justify-center pb-4'\r\n }`}\r\n >\r\n {/* Nav User */}\r\n <NavUser signOut={signOut} />\r\n\r\n {!isCollapsed ? (\r\n <Link\r\n href=\"https://collabdt.org/\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"w-full\"\r\n >\r\n <Button\r\n title={t('home')}\r\n variant=\"ghost\"\r\n className=\"text-xs scale-[85%] py-0 my-0 w-full flex flex-row items-center justify-center gap-2\"\r\n >\r\n <CdtIcon monochromatic />\r\n <span>{t('home')}</span>\r\n </Button>\r\n </Link>\r\n ) : null}\r\n </div>\r\n </Sidebar>\r\n </>\r\n )\r\n}"],"mappings":";AA8DI,mBASQ,KA2CI,YApDZ;AAtDJ,SAAS,cAAc;AAGvB,YAAY,QAAQ;AAEpB,SAAS,uBAAuB;AAChC,SAAS,eAAe;AACxB,OAAO,UAAU;AACjB,SAAS,SAAS,YAAY,eAAe;AAC7C,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAEzB,MAAM,qBAAqB,CAChC,QACA,iBACA,iBACA,iBACA,SACA,kBACG;AAEH,kBAAgB,IAAI;AACpB,kBAAgB,IAAI;AACpB,kBAAgB,IAAI;AACpB,UAAQ,OAAO;AAEf,gBAAc;AAAA,IACZ,MAAM;AAAA,IACN,SAAS,EAAE,eAAe,OAAO;AAAA,EACnC,CAAC;AACH;AAOO,SAAS,WAAW,EAAE,UAAU,QAAQ,GAAoB;AAEjE,QAAM,IAAI,gBAAgB,YAAY;AAEtC,QAAM,EAAE,OAAO,WAAW,IAAI,gBAAgB;AAE9C,QAAM,EAAE,cAAc,UAAU,YAAY,kBAAkB,IAAI,WAAW;AAE7E,QAAM,EAAE,cAAc,IAAI,WAAW;AAGrC,QAAM,cAAc,WAAW,CAAC,aAAa,iBAAiB;AAG9D,QAAM,kBAAkB,kBAAkB,YAAY,OAAO,cAAc;AAE3E,SACE,iCAEG;AAAA,gBAAY,eACX,oBAAC,SAAI,IAAG,gCAA+B,WAAU,sGAC/C;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAU;AAAA,QACV,OAAO,EAAE,QAAQ,mCAAmC,YAAY,QAAQ,WAAW,kCAAkC;AAAA,QAErH,8BAAC,GAAG,cAAH,EAAgB,WAAU,OAAM;AAAA;AAAA,IACnC,GACF;AAAA,IAEF,qBAAC,WAAQ,aAAa,iBAAiB,WAAU,uCAE7C;AAAA,uBAAiB,cACjB,oBAAC,SAAI,IAAG,yBAAwB,WAAW,oFAAoF,WAAW,KAAK,EAAE,IAC/I,8BAAC,YAAO,SAAS,mBAAmB,WAAU,gDAC5C,8BAAC,GAAG,GAAH,EAAK,WAAU,OAAM,GACxB,GACF;AAAA,MAGD,CAAC,YAAY,iBAAiB,cAC7B,oBAAC,SAAI,IAAG,yBAAwB,WAAU,gHACxC;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UACV,OAAO,EAAE,aAAa,mCAAmC,WAAW,kCAAkC;AAAA,UAEtG,8BAAC,GAAG,cAAH,EAAgB,WAAU,OAAM;AAAA;AAAA,MACnC,GACF;AAAA,MAED;AAAA,MACD;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,wBACT,iBAAiB,aACb,gCACA,qBACN;AAAA,UAGE;AAAA,gCAAC,WAAQ,SAAkB;AAAA,YAE1B,CAAC,cACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,QAAO;AAAA,gBACP,KAAI;AAAA,gBACJ,WAAU;AAAA,gBAEV;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO,EAAE,MAAM;AAAA,oBACf,SAAQ;AAAA,oBACR,WAAU;AAAA,oBAEV;AAAA,0CAAC,WAAQ,eAAa,MAAC;AAAA,sBACvB,oBAAC,UAAM,YAAE,MAAM,GAAE;AAAA;AAAA;AAAA,gBACnB;AAAA;AAAA,YACF,IACE;AAAA;AAAA;AAAA,MACN;AAAA,OACJ;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollapsibleSensorItem.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/Sensors/CollapsibleSensorItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAS9B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"CollapsibleSensorItem.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/Sensors/CollapsibleSensorItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAS9B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAS3D,KAAK,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;AAExD,UAAU,0BAA0B;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACrD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,UAAU,EACV,QAAQ,EACR,KAAS,EACT,SAAgB,EAChB,YAAY,EACZ,YAAY,EACb,EAAE,0BAA0B,qBAqO5B"}
|
|
@@ -14,6 +14,7 @@ import { useCoreHooks } from "../../../hooks/provider";
|
|
|
14
14
|
import { useSession } from "next-auth/react";
|
|
15
15
|
import { SensorChart } from "./SensorChart";
|
|
16
16
|
import { SensorTagsSection } from "./SensorTagsSection";
|
|
17
|
+
import { useAppConfigContext } from "../../../store/AppConfig/context";
|
|
17
18
|
function CollapsibleSensorItem({
|
|
18
19
|
sensor,
|
|
19
20
|
sensorType,
|
|
@@ -29,7 +30,8 @@ function CollapsibleSensorItem({
|
|
|
29
30
|
const [sensorData, setSensorData] = React.useState([]);
|
|
30
31
|
const [isLoadingData, setIsLoadingData] = React.useState(false);
|
|
31
32
|
const prevVisibleRef = React.useRef(isVisible);
|
|
32
|
-
const
|
|
33
|
+
const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext();
|
|
34
|
+
const dataPath = `${minioUrl != null ? minioUrl : ""}/sensors/${sensor.url}`;
|
|
33
35
|
const typeIcon = (sensorType == null ? void 0 : sensorType.icon) || "Radio";
|
|
34
36
|
const typeName = (_a = sensorType == null ? void 0 : sensorType.name.replace(/_/g, " ")) != null ? _a : "Unknown";
|
|
35
37
|
const SensorIcon = LR[typeIcon] || LR.Radio;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/core/components/ui/Sensors/CollapsibleSensorItem.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 { Button } from '../Button'\r\nimport { Badge } from '../Badge'\r\nimport { Avatar, AvatarFallback } from '../Avatar'\r\nimport { UserAvatar } from '../UserAvatar'\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { format } from 'date-fns'\r\nimport { cn } from '../../../utils/utils'\r\nimport { Sensor, SensorType } from '../../../types/dbTypes'\r\nimport { useUser } from '../../../hooks/users/users'\r\nimport { useCoreHooks } from '../../../hooks/provider'\r\nimport { useSession } from 'next-auth/react'\r\nimport { SensorChart } from './SensorChart'\r\nimport { SensorTagsSection } from './SensorTagsSection'\r\nimport type { ChartConfig } from '../chart'\r\n\r\ntype SensorAction = 'view' | 'edit' | 'delete' | 'reply'\r\n\r\ninterface CollapsibleSensorItemProps {\r\n sensor: Sensor\r\n sensorType: SensorType\r\n onAction?: (action: SensorAction, id: number) => void\r\n depth?: number\r\n isVisible?: boolean\r\n onMouseEnter?: () => void\r\n onMouseLeave?: () => void\r\n}\r\n\r\nexport function CollapsibleSensorItem({\r\n sensor,\r\n sensorType,\r\n onAction,\r\n depth = 0,\r\n isVisible = true,\r\n onMouseEnter,\r\n onMouseLeave\r\n}: CollapsibleSensorItemProps) {\r\n const t = useTranslations('SensorsSection')\r\n const [isExpanded, setIsExpanded] = React.useState(false)\r\n const [sensorData, setSensorData] = React.useState<{ time: string; value: number }[]>([])\r\n const [isLoadingData, setIsLoadingData] = React.useState(false)\r\n const prevVisibleRef = React.useRef(isVisible)\r\n\r\n const dataPath = `${process.env.NEXT_PUBLIC_MINIO_BUCKET_URL}/sensors/${sensor.url}`\r\n\r\n const typeIcon = sensorType?.icon || 'Radio'\r\n const typeName = sensorType?.name.replace(/_/g, ' ') ?? 'Unknown' \r\n\r\n const SensorIcon = LR[typeIcon] || LR.Radio\r\n\r\n // Auto-collapse when visibility turns off\r\n React.useEffect(() => {\r\n const prevVisible = prevVisibleRef.current\r\n \r\n if (prevVisible && !isVisible) {\r\n // Just turned invisible - collapse\r\n setIsExpanded(false)\r\n }\r\n \r\n prevVisibleRef.current = isVisible\r\n }, [isVisible])\r\n\r\n // Fetch and parse CSV data\r\n React.useEffect(() => {\r\n const fetchCSVData = async () => {\r\n setIsLoadingData(true)\r\n try {\r\n const response = await fetch(dataPath)\r\n const csvText = await response.text()\r\n \r\n // Parse CSV: format is \"time,value\" (e.g., \"0:00:00,7.4\")\r\n const lines = csvText.trim().split('\\n')\r\n const parsed = lines.map(line => {\r\n const [time, valueStr] = line.split(',')\r\n return {\r\n time: time.trim(),\r\n value: parseFloat(valueStr.trim())\r\n }\r\n }).filter(item => !isNaN(item.value)) // Filter out any invalid entries\r\n \r\n setSensorData(parsed)\r\n } catch (error) {\r\n console.error('Error fetching sensor data:', error)\r\n // Fallback to empty array on error\r\n setSensorData([])\r\n } finally {\r\n setIsLoadingData(false)\r\n }\r\n }\r\n\r\n if (isExpanded) {\r\n fetchCSVData()\r\n }\r\n }, [dataPath, isExpanded])\r\n\r\n const chartConfig = {\r\n value: {\r\n label: typeName,\r\n color: \"hsl(var(--chart-1))\",\r\n },\r\n } satisfies ChartConfig\r\n\r\n const user = useSession().data?.user\r\n\r\n const indentClass = depth > 0 ? `ml-${Math.min(depth * 4, 12)}` : ''\r\n\r\n const { user: author } = useUser(String(sensor.authorId))\r\n let authorName: string | undefined = author?.name ?? 'Unknown User'\r\n\r\n const { sensor: sensorHooks } = useCoreHooks()\r\n const { updateSensor } = sensorHooks.useSensor(sensor.id)\r\n\r\n const handleAddTag = async (tag: string) => {\r\n const currentTags = sensor.tags ?? []\r\n await updateSensor({ tags: [...currentTags, tag] })\r\n }\r\n\r\n const handleDeleteTag = async (tag: string) => {\r\n const currentTags = sensor.tags ?? []\r\n await updateSensor({ tags: currentTags.filter(t => t !== tag) })\r\n }\r\n\r\n return (\r\n <div \r\n className={cn(\r\n \"border rounded-md overflow-hidden transition-opacity\",\r\n indentClass,\r\n !isVisible && \"opacity-70\"\r\n )}\r\n onMouseEnter={onMouseEnter}\r\n onMouseLeave={onMouseLeave}\r\n >\r\n {/* Sensor Header */}\r\n <div className=\"flex items-start justify-between p-3 hover:bg-accent/50 transition-colors\">\r\n <div className=\"flex items-start gap-3 flex-1 min-w-0\">\r\n <Button\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n className={cn(\"h-6 w-6 p-0 mt-1\", !isVisible && \"opacity-70\")}\r\n onClick={() => setIsExpanded(!isExpanded)}\r\n >\r\n <LR.ChevronRight\r\n className={cn(\r\n \"h-4 w-4 transition-transform\",\r\n isExpanded && \"rotate-90\"\r\n )}\r\n />\r\n </Button>\r\n\r\n <div className={cn(\r\n \"h-8 w-8 mt-1 rounded-full bg-primary flex items-center justify-center flex-shrink-0\",\r\n !isVisible && \"opacity-70 grayscale\"\r\n )}>\r\n <SensorIcon className={cn(\"h-4 w-4 text-primary-foreground\", !isVisible && \"opacity-70\")} />\r\n </div>\r\n\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center gap-2\">\r\n <span className={cn(\"text-sm font-medium\", isVisible ? \"text-foreground\" : \"text-muted-foreground\")}>\r\n {sensor.name}\r\n </span>\r\n {sensor.updatedAt !== sensor.createdAt && (\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {t('edited')}\r\n </Badge>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Action Buttons */}\r\n {onAction && (\r\n <div className={cn(\"flex items-center gap-0 flex-shrink-0\", !isVisible && \"opacity-70\")}>\r\n {user?.id === String(sensor.authorId) && (\r\n <>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 p-0\"\r\n onClick={() => onAction('edit', sensor.id)}\r\n title={t('editSensor')}\r\n >\r\n <LR.Pencil className=\"h-4 w-4\" />\r\n </Button>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 p-0\"\r\n onClick={() => onAction('delete', sensor.id)}\r\n title={t('deleteSensor')}\r\n >\r\n <LR.Trash2 className=\"h-4 w-4\" />\r\n </Button>\r\n </>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Expanded Content */ }\r\n {\r\n isExpanded && (\r\n <div className=\"border-t bg-muted/30\">\r\n <div className=\"p-4 space-y-4\">\r\n {/* Sensor Information */}\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center justify-between\">\r\n <span className=\"text-xs text-muted-foreground\">\r\n {format(new Date(sensor.createdAt), 'PPp')}\r\n </span>\r\n <Badge variant=\"secondary\" className=\"text-xs\">\r\n {typeName}\r\n </Badge>\r\n </div>\r\n \r\n <div className=\"grid grid-cols-2 gap-2 text-sm\">\r\n <div>\r\n <span className=\"text-muted-foreground\">Name:</span>\r\n <span className=\"ml-2 font-medium\">{sensor.name}</span>\r\n </div>\r\n <div>\r\n <span className=\"text-muted-foreground\">Format:</span>\r\n <span className=\"ml-2 font-medium\">{sensor.dataFormat}</span>\r\n </div>\r\n </div>\r\n\r\n {/* Author Information */}\r\n <div className=\"flex items-center gap-2 pt-2\">\r\n <span className=\"text-muted-foreground text-sm\">Author:</span>\r\n <Avatar className=\"h-5 w-5 rounded-full overflow-hidden\">\r\n <UserAvatar imageFileId={author?.imageFileId} name={authorName} />\r\n </Avatar>\r\n <span className=\"text-sm font-medium\">{authorName}</span>\r\n </div>\r\n </div>\r\n\r\n {/* Sensor Data Chart */}\r\n <SensorChart\r\n sensorData={sensorData}\r\n isLoadingData={isLoadingData}\r\n sensorName={sensor.name}\r\n sensorType={sensorType}\r\n updateFrequency={sensor.updateFrequency}\r\n chartConfig={chartConfig}\r\n />\r\n </div>\r\n <div>\r\n <SensorTagsSection\r\n tags={sensor.tags ?? []}\r\n onAdd={handleAddTag}\r\n onDelete={handleDeleteTag}\r\n translations={{\r\n addTag: t('addTag'),\r\n removeTag: t('removeTag'),\r\n cancel: t('cancel'),\r\n newTagPlaceholder: t('newTagPlaceholder'),\r\n }}\r\n />\r\n </div>\r\n\r\n </div>\r\n )\r\n }\r\n </div >\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","t"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/core/components/ui/Sensors/CollapsibleSensorItem.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 { Button } from '../Button'\r\nimport { Badge } from '../Badge'\r\nimport { Avatar, AvatarFallback } from '../Avatar'\r\nimport { UserAvatar } from '../UserAvatar'\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { format } from 'date-fns'\r\nimport { cn } from '../../../utils/utils'\r\nimport { Sensor, SensorType } from '../../../types/dbTypes'\r\nimport { useUser } from '../../../hooks/users/users'\r\nimport { useCoreHooks } from '../../../hooks/provider'\r\nimport { useSession } from 'next-auth/react'\r\nimport { SensorChart } from './SensorChart'\r\nimport { SensorTagsSection } from './SensorTagsSection'\r\nimport type { ChartConfig } from '../chart'\r\nimport { useAppConfigContext } from '../../../store/AppConfig/context'\r\n\r\ntype SensorAction = 'view' | 'edit' | 'delete' | 'reply'\r\n\r\ninterface CollapsibleSensorItemProps {\r\n sensor: Sensor\r\n sensorType: SensorType\r\n onAction?: (action: SensorAction, id: number) => void\r\n depth?: number\r\n isVisible?: boolean\r\n onMouseEnter?: () => void\r\n onMouseLeave?: () => void\r\n}\r\n\r\nexport function CollapsibleSensorItem({\r\n sensor,\r\n sensorType,\r\n onAction,\r\n depth = 0,\r\n isVisible = true,\r\n onMouseEnter,\r\n onMouseLeave\r\n}: CollapsibleSensorItemProps) {\r\n const t = useTranslations('SensorsSection')\r\n const [isExpanded, setIsExpanded] = React.useState(false)\r\n const [sensorData, setSensorData] = React.useState<{ time: string; value: number }[]>([])\r\n const [isLoadingData, setIsLoadingData] = React.useState(false)\r\n const prevVisibleRef = React.useRef(isVisible)\r\n\r\n const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext()\r\n const dataPath = `${minioUrl ?? ''}/sensors/${sensor.url}`\r\n const typeIcon = sensorType?.icon || 'Radio'\r\n const typeName = sensorType?.name.replace(/_/g, ' ') ?? 'Unknown' \r\n\r\n const SensorIcon = LR[typeIcon] || LR.Radio\r\n\r\n // Auto-collapse when visibility turns off\r\n React.useEffect(() => {\r\n const prevVisible = prevVisibleRef.current\r\n \r\n if (prevVisible && !isVisible) {\r\n // Just turned invisible - collapse\r\n setIsExpanded(false)\r\n }\r\n \r\n prevVisibleRef.current = isVisible\r\n }, [isVisible])\r\n\r\n // Fetch and parse CSV data\r\n React.useEffect(() => {\r\n const fetchCSVData = async () => {\r\n setIsLoadingData(true)\r\n try {\r\n const response = await fetch(dataPath)\r\n const csvText = await response.text()\r\n \r\n // Parse CSV: format is \"time,value\" (e.g., \"0:00:00,7.4\")\r\n const lines = csvText.trim().split('\\n')\r\n const parsed = lines.map(line => {\r\n const [time, valueStr] = line.split(',')\r\n return {\r\n time: time.trim(),\r\n value: parseFloat(valueStr.trim())\r\n }\r\n }).filter(item => !isNaN(item.value)) // Filter out any invalid entries\r\n \r\n setSensorData(parsed)\r\n } catch (error) {\r\n console.error('Error fetching sensor data:', error)\r\n // Fallback to empty array on error\r\n setSensorData([])\r\n } finally {\r\n setIsLoadingData(false)\r\n }\r\n }\r\n\r\n if (isExpanded) {\r\n fetchCSVData()\r\n }\r\n }, [dataPath, isExpanded])\r\n\r\n const chartConfig = {\r\n value: {\r\n label: typeName,\r\n color: \"hsl(var(--chart-1))\",\r\n },\r\n } satisfies ChartConfig\r\n\r\n const user = useSession().data?.user\r\n\r\n const indentClass = depth > 0 ? `ml-${Math.min(depth * 4, 12)}` : ''\r\n\r\n const { user: author } = useUser(String(sensor.authorId))\r\n let authorName: string | undefined = author?.name ?? 'Unknown User'\r\n\r\n const { sensor: sensorHooks } = useCoreHooks()\r\n const { updateSensor } = sensorHooks.useSensor(sensor.id)\r\n\r\n const handleAddTag = async (tag: string) => {\r\n const currentTags = sensor.tags ?? []\r\n await updateSensor({ tags: [...currentTags, tag] })\r\n }\r\n\r\n const handleDeleteTag = async (tag: string) => {\r\n const currentTags = sensor.tags ?? []\r\n await updateSensor({ tags: currentTags.filter(t => t !== tag) })\r\n }\r\n\r\n return (\r\n <div \r\n className={cn(\r\n \"border rounded-md overflow-hidden transition-opacity\",\r\n indentClass,\r\n !isVisible && \"opacity-70\"\r\n )}\r\n onMouseEnter={onMouseEnter}\r\n onMouseLeave={onMouseLeave}\r\n >\r\n {/* Sensor Header */}\r\n <div className=\"flex items-start justify-between p-3 hover:bg-accent/50 transition-colors\">\r\n <div className=\"flex items-start gap-3 flex-1 min-w-0\">\r\n <Button\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n className={cn(\"h-6 w-6 p-0 mt-1\", !isVisible && \"opacity-70\")}\r\n onClick={() => setIsExpanded(!isExpanded)}\r\n >\r\n <LR.ChevronRight\r\n className={cn(\r\n \"h-4 w-4 transition-transform\",\r\n isExpanded && \"rotate-90\"\r\n )}\r\n />\r\n </Button>\r\n\r\n <div className={cn(\r\n \"h-8 w-8 mt-1 rounded-full bg-primary flex items-center justify-center flex-shrink-0\",\r\n !isVisible && \"opacity-70 grayscale\"\r\n )}>\r\n <SensorIcon className={cn(\"h-4 w-4 text-primary-foreground\", !isVisible && \"opacity-70\")} />\r\n </div>\r\n\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center gap-2\">\r\n <span className={cn(\"text-sm font-medium\", isVisible ? \"text-foreground\" : \"text-muted-foreground\")}>\r\n {sensor.name}\r\n </span>\r\n {sensor.updatedAt !== sensor.createdAt && (\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {t('edited')}\r\n </Badge>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Action Buttons */}\r\n {onAction && (\r\n <div className={cn(\"flex items-center gap-0 flex-shrink-0\", !isVisible && \"opacity-70\")}>\r\n {user?.id === String(sensor.authorId) && (\r\n <>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 p-0\"\r\n onClick={() => onAction('edit', sensor.id)}\r\n title={t('editSensor')}\r\n >\r\n <LR.Pencil className=\"h-4 w-4\" />\r\n </Button>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 p-0\"\r\n onClick={() => onAction('delete', sensor.id)}\r\n title={t('deleteSensor')}\r\n >\r\n <LR.Trash2 className=\"h-4 w-4\" />\r\n </Button>\r\n </>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Expanded Content */ }\r\n {\r\n isExpanded && (\r\n <div className=\"border-t bg-muted/30\">\r\n <div className=\"p-4 space-y-4\">\r\n {/* Sensor Information */}\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center justify-between\">\r\n <span className=\"text-xs text-muted-foreground\">\r\n {format(new Date(sensor.createdAt), 'PPp')}\r\n </span>\r\n <Badge variant=\"secondary\" className=\"text-xs\">\r\n {typeName}\r\n </Badge>\r\n </div>\r\n \r\n <div className=\"grid grid-cols-2 gap-2 text-sm\">\r\n <div>\r\n <span className=\"text-muted-foreground\">Name:</span>\r\n <span className=\"ml-2 font-medium\">{sensor.name}</span>\r\n </div>\r\n <div>\r\n <span className=\"text-muted-foreground\">Format:</span>\r\n <span className=\"ml-2 font-medium\">{sensor.dataFormat}</span>\r\n </div>\r\n </div>\r\n\r\n {/* Author Information */}\r\n <div className=\"flex items-center gap-2 pt-2\">\r\n <span className=\"text-muted-foreground text-sm\">Author:</span>\r\n <Avatar className=\"h-5 w-5 rounded-full overflow-hidden\">\r\n <UserAvatar imageFileId={author?.imageFileId} name={authorName} />\r\n </Avatar>\r\n <span className=\"text-sm font-medium\">{authorName}</span>\r\n </div>\r\n </div>\r\n\r\n {/* Sensor Data Chart */}\r\n <SensorChart\r\n sensorData={sensorData}\r\n isLoadingData={isLoadingData}\r\n sensorName={sensor.name}\r\n sensorType={sensorType}\r\n updateFrequency={sensor.updateFrequency}\r\n chartConfig={chartConfig}\r\n />\r\n </div>\r\n <div>\r\n <SensorTagsSection\r\n tags={sensor.tags ?? []}\r\n onAdd={handleAddTag}\r\n onDelete={handleDeleteTag}\r\n translations={{\r\n addTag: t('addTag'),\r\n removeTag: t('removeTag'),\r\n cancel: t('cancel'),\r\n newTagPlaceholder: t('newTagPlaceholder'),\r\n }}\r\n />\r\n </div>\r\n\r\n </div>\r\n )\r\n }\r\n </div >\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","t"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSensorMarkers.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useSensorMarkers.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"names":[],"mappings":"AAiBA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM;iCAoDP;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;8BAMtC,MAAM;;EAoE1D"}
|
|
@@ -28,9 +28,11 @@ import { useCoreHooks } from "../../../../../../../hooks/provider";
|
|
|
28
28
|
import { renderCSS2DMarkers } from "./renderCSS2DMarkers";
|
|
29
29
|
import BimSensor from "./BimSensor";
|
|
30
30
|
import { UNTAGGED_TAG } from "../../../../../../ui/Sensors/SensorsSection";
|
|
31
|
+
import { useAppConfigContext } from "../../../../../../../store/AppConfig/context";
|
|
31
32
|
function useSensorMarkers(world, buildingId) {
|
|
32
33
|
const { state: menusState } = React.useContext(MenusContext);
|
|
33
34
|
const { currentSensorId, visibleSensorTypes, visibleSensorTags } = menusState.menus;
|
|
35
|
+
const { state: appConfigState } = useAppConfigContext();
|
|
34
36
|
const registry = React.useRef(/* @__PURE__ */ new Map());
|
|
35
37
|
const { sensors } = useSensors();
|
|
36
38
|
const { users } = useUsers();
|
|
@@ -110,12 +112,12 @@ function useSensorMarkers(world, buildingId) {
|
|
|
110
112
|
component: BimSensor,
|
|
111
113
|
hooksContextValue: coreHooks,
|
|
112
114
|
propsMapper: (sensor) => {
|
|
113
|
-
var _a;
|
|
115
|
+
var _a, _b;
|
|
114
116
|
return {
|
|
115
117
|
sensorName: sensor.name,
|
|
116
118
|
sensorType: sensorTypes.find((t) => t.id === sensor.typeId),
|
|
117
119
|
tags: sensor.tags,
|
|
118
|
-
dataUrl: ((_a = sensor.url) == null ? void 0 : _a.startsWith("http")) ? sensor.url : `${
|
|
120
|
+
dataUrl: ((_a = sensor.url) == null ? void 0 : _a.startsWith("http")) ? sensor.url : `${(_b = appConfigState.runtimeConfig.minioUrl) != null ? _b : ""}/sensors/${sensor.url}`,
|
|
119
121
|
dataFormat: sensor.dataFormat,
|
|
120
122
|
updateFrequency: sensor.updateFrequency,
|
|
121
123
|
buildingId: sensor.buildingId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"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 { MenusContext } from \"../../../../../../../store\"\r\nimport { ViewerNames } from \"../../../../../../../types/dbTypes\"\r\nimport { useSensors, useSensor } from \"../../../../../../../hooks/sensors/sensors\"\r\nimport { useUsers } from \"../../../../../../../hooks/users/users\"\r\nimport { useSensorTypes } from \"../../../../../../../hooks/sensorTypes/sensorTypes\"\r\nimport { useCoreHooks } from \"../../../../../../../hooks/provider\"\r\nimport { renderCSS2DMarkers, type MarkerRef } from \"./renderCSS2DMarkers\"\r\nimport BimSensor from \"./BimSensor\"\r\nimport { UNTAGGED_TAG } from \"../../../../../../ui/Sensors/SensorsSection\"\r\n\r\nexport function useSensorMarkers(world: any, buildingId: number) {\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { currentSensorId, visibleSensorTypes, visibleSensorTags } = menusState.menus\r\n\r\n const registry = React.useRef<Map<string, MarkerRef>>(new Map())\r\n\r\n const { sensors } = useSensors()\r\n const { users } = useUsers()\r\n const { sensorTypes } = useSensorTypes()\r\n const coreHooks = useCoreHooks()\r\n\r\n const [sensorToDelete, setSensorToDelete] = React.useState<number | null>(null)\r\n const { deleteSensor } = useSensor(sensorToDelete)\r\n\r\n const eligibleSensors = sensors\r\n .filter((sensor) => {\r\n const { x, y, z, viewer } = sensor\r\n if (x == null || y == null || z == null) return false\r\n if (viewer !== ViewerNames.bim) return false\r\n if (buildingId !== -1 && sensor.buildingId !== buildingId) return false\r\n return true\r\n })\r\n .map((sensor) => {\r\n const user = users.find(u => u.id === sensor.authorId)\r\n const sensorType = sensorTypes.find(t => t.id === sensor.typeId)\r\n return {\r\n ...sensor,\r\n authorName: user?.name ?? \"Unknown User\",\r\n imageFileId: user?.imageFileId ?? \"images/default-avatar.svg\",\r\n sensorType,\r\n }\r\n })\r\n\r\n // Stable ref so the render effect reads current sensors without re-running on every change\r\n const eligibleSensorsRef = React.useRef(eligibleSensors)\r\n eligibleSensorsRef.current = eligibleSensors\r\n\r\n React.useEffect(() => {\r\n if (sensorToDelete !== null) {\r\n deleteSensor()\r\n setSensorToDelete(null)\r\n }\r\n }, [sensorToDelete, deleteSensor])\r\n\r\n const handleRemoveSensor = React.useCallback((sensorId: number) => {\r\n setSensorToDelete(sensorId)\r\n }, [])\r\n\r\n // Pending markers for loading indicators while sensor is being created\r\n const [pendingSensors, setPendingSensors] = React.useState<Array<{ id: number; x: number; y: number; z: number }>>([])\r\n\r\n const addPendingSensor = React.useCallback((position: { x: number; y: number; z: number }) => {\r\n const id = -Date.now()\r\n setPendingSensors(prev => [...prev, { id, ...position }])\r\n return id\r\n }, [])\r\n\r\n const removePendingSensor = React.useCallback((id: number) => {\r\n setPendingSensors(prev => prev.filter(p => p.id !== id))\r\n }, [])\r\n\r\n // Render sensor markers with visibility filtering\r\n React.useEffect(() => {\r\n const typesVisible = visibleSensorTypes?.[ViewerNames.bim] || []\r\n const tagsVisible = visibleSensorTags?.[ViewerNames.bim] || []\r\n\r\n const visibleSensors = eligibleSensorsRef.current.filter(sensor => {\r\n const matchesType = typesVisible.includes(sensor.typeId)\r\n const hasNoTags = !sensor.tags?.length\r\n const matchesTag = hasNoTags\r\n ? tagsVisible.includes(UNTAGGED_TAG)\r\n : sensor.tags?.some((tag: string) => tagsVisible.includes(tag)) ?? false\r\n return matchesType || matchesTag\r\n })\r\n\r\n const allSensors = [\r\n ...visibleSensors.map(s => ({ ...s, isPending: false })),\r\n ...pendingSensors.map(p => ({\r\n id: p.id,\r\n name: \"Creating...\",\r\n sensorType: undefined,\r\n typeId: undefined,\r\n x: p.x,\r\n y: p.y,\r\n z: p.z,\r\n url: \"\",\r\n dataFormat: \"Json\",\r\n updateFrequency: 0,\r\n createdAt: new Date().toISOString(),\r\n buildingId,\r\n tags: [],\r\n isPending: true,\r\n })),\r\n ]\r\n\r\n renderCSS2DMarkers(world, {\r\n items: allSensors,\r\n markerIdKey: \"sensorId\",\r\n registry,\r\n component: BimSensor,\r\n hooksContextValue: coreHooks,\r\n propsMapper: (sensor) => ({\r\n sensorName: sensor.name,\r\n sensorType: sensorTypes.find(t => t.id === sensor.typeId),\r\n tags: sensor.tags,\r\n dataUrl: sensor.url?.startsWith(\"http\")\r\n ? sensor.url\r\n : `${
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"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 { MenusContext } from \"../../../../../../../store\"\r\nimport { ViewerNames } from \"../../../../../../../types/dbTypes\"\r\nimport { useSensors, useSensor } from \"../../../../../../../hooks/sensors/sensors\"\r\nimport { useUsers } from \"../../../../../../../hooks/users/users\"\r\nimport { useSensorTypes } from \"../../../../../../../hooks/sensorTypes/sensorTypes\"\r\nimport { useCoreHooks } from \"../../../../../../../hooks/provider\"\r\nimport { renderCSS2DMarkers, type MarkerRef } from \"./renderCSS2DMarkers\"\r\nimport BimSensor from \"./BimSensor\"\r\nimport { UNTAGGED_TAG } from \"../../../../../../ui/Sensors/SensorsSection\"\r\nimport { useAppConfigContext } from \"../../../../../../../store/AppConfig/context\"\r\n\r\nexport function useSensorMarkers(world: any, buildingId: number) {\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { currentSensorId, visibleSensorTypes, visibleSensorTags } = menusState.menus\r\n const { state: appConfigState } = useAppConfigContext()\r\n\r\n const registry = React.useRef<Map<string, MarkerRef>>(new Map())\r\n\r\n const { sensors } = useSensors()\r\n const { users } = useUsers()\r\n const { sensorTypes } = useSensorTypes()\r\n const coreHooks = useCoreHooks()\r\n\r\n const [sensorToDelete, setSensorToDelete] = React.useState<number | null>(null)\r\n const { deleteSensor } = useSensor(sensorToDelete)\r\n\r\n const eligibleSensors = sensors\r\n .filter((sensor) => {\r\n const { x, y, z, viewer } = sensor\r\n if (x == null || y == null || z == null) return false\r\n if (viewer !== ViewerNames.bim) return false\r\n if (buildingId !== -1 && sensor.buildingId !== buildingId) return false\r\n return true\r\n })\r\n .map((sensor) => {\r\n const user = users.find(u => u.id === sensor.authorId)\r\n const sensorType = sensorTypes.find(t => t.id === sensor.typeId)\r\n return {\r\n ...sensor,\r\n authorName: user?.name ?? \"Unknown User\",\r\n imageFileId: user?.imageFileId ?? \"images/default-avatar.svg\",\r\n sensorType,\r\n }\r\n })\r\n\r\n // Stable ref so the render effect reads current sensors without re-running on every change\r\n const eligibleSensorsRef = React.useRef(eligibleSensors)\r\n eligibleSensorsRef.current = eligibleSensors\r\n\r\n React.useEffect(() => {\r\n if (sensorToDelete !== null) {\r\n deleteSensor()\r\n setSensorToDelete(null)\r\n }\r\n }, [sensorToDelete, deleteSensor])\r\n\r\n const handleRemoveSensor = React.useCallback((sensorId: number) => {\r\n setSensorToDelete(sensorId)\r\n }, [])\r\n\r\n // Pending markers for loading indicators while sensor is being created\r\n const [pendingSensors, setPendingSensors] = React.useState<Array<{ id: number; x: number; y: number; z: number }>>([])\r\n\r\n const addPendingSensor = React.useCallback((position: { x: number; y: number; z: number }) => {\r\n const id = -Date.now()\r\n setPendingSensors(prev => [...prev, { id, ...position }])\r\n return id\r\n }, [])\r\n\r\n const removePendingSensor = React.useCallback((id: number) => {\r\n setPendingSensors(prev => prev.filter(p => p.id !== id))\r\n }, [])\r\n\r\n // Render sensor markers with visibility filtering\r\n React.useEffect(() => {\r\n const typesVisible = visibleSensorTypes?.[ViewerNames.bim] || []\r\n const tagsVisible = visibleSensorTags?.[ViewerNames.bim] || []\r\n\r\n const visibleSensors = eligibleSensorsRef.current.filter(sensor => {\r\n const matchesType = typesVisible.includes(sensor.typeId)\r\n const hasNoTags = !sensor.tags?.length\r\n const matchesTag = hasNoTags\r\n ? tagsVisible.includes(UNTAGGED_TAG)\r\n : sensor.tags?.some((tag: string) => tagsVisible.includes(tag)) ?? false\r\n return matchesType || matchesTag\r\n })\r\n\r\n const allSensors = [\r\n ...visibleSensors.map(s => ({ ...s, isPending: false })),\r\n ...pendingSensors.map(p => ({\r\n id: p.id,\r\n name: \"Creating...\",\r\n sensorType: undefined,\r\n typeId: undefined,\r\n x: p.x,\r\n y: p.y,\r\n z: p.z,\r\n url: \"\",\r\n dataFormat: \"Json\",\r\n updateFrequency: 0,\r\n createdAt: new Date().toISOString(),\r\n buildingId,\r\n tags: [],\r\n isPending: true,\r\n })),\r\n ]\r\n\r\n renderCSS2DMarkers(world, {\r\n items: allSensors,\r\n markerIdKey: \"sensorId\",\r\n registry,\r\n component: BimSensor,\r\n hooksContextValue: coreHooks,\r\n propsMapper: (sensor) => ({\r\n sensorName: sensor.name,\r\n sensorType: sensorTypes.find(t => t.id === sensor.typeId),\r\n tags: sensor.tags,\r\n dataUrl: sensor.url?.startsWith(\"http\")\r\n ? sensor.url\r\n : `${appConfigState.runtimeConfig.minioUrl ?? ''}/sensors/${sensor.url}`,\r\n dataFormat: sensor.dataFormat,\r\n updateFrequency: sensor.updateFrequency,\r\n buildingId: sensor.buildingId,\r\n timestamp: new Date(sensor.createdAt),\r\n highlight: currentSensorId === sensor.id,\r\n }),\r\n sphereColor: \"#10b981\",\r\n isVisible: true,\r\n onRemove: handleRemoveSensor,\r\n })\r\n }, [world, sensors, pendingSensors, handleRemoveSensor, visibleSensorTypes, visibleSensorTags, buildingId, currentSensorId, sensorTypes, coreHooks])\r\n\r\n const sensorCount = sensors.filter(\r\n s => s.viewer === ViewerNames.bim && (!buildingId || buildingId === -1 || s.buildingId === buildingId)\r\n ).length\r\n\r\n return { addPendingSensor, removePendingSensor, sensorCount }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RowActions.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/datasets/RowActions.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"RowActions.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/datasets/RowActions.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAG7D,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAA;IAChB,iBAAiB,EAAE,OAAO,EAAE,CAAA;IAC5B,oBAAoB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;CACtE;AAED,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,OAAO,EACP,iBAAiB,EACjB,oBAAoB,GACrB,EAAE,eAAe,qBAqQjB"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { usePermissions } from "../../../../store";
|
|
5
|
+
import { useAppConfigContext } from "../../../../store/AppConfig/context";
|
|
5
6
|
import { handleFavouriteDataset } from "./utils";
|
|
6
7
|
import { Checkbox, Button } from "../../../ui/";
|
|
7
8
|
import * as LR from "lucide-react";
|
|
@@ -13,6 +14,7 @@ function RowActions({
|
|
|
13
14
|
setFavouriteDatasets
|
|
14
15
|
}) {
|
|
15
16
|
const { ability } = usePermissions();
|
|
17
|
+
const { state: appConfigState } = useAppConfigContext();
|
|
16
18
|
const { state: datasetsState, dispatch: datasetsDispatch } = React.useContext(DatasetsContext);
|
|
17
19
|
const { addedDatasets } = datasetsState.datasets;
|
|
18
20
|
const orgDatasets = datasetsState.datasets.datasets;
|
|
@@ -87,7 +89,7 @@ function RowActions({
|
|
|
87
89
|
}
|
|
88
90
|
const result = await res.json();
|
|
89
91
|
setPublished(true);
|
|
90
|
-
const tileBaseUrl = ((_b =
|
|
92
|
+
const tileBaseUrl = ((_b = appConfigState.runtimeConfig.martinUrl) != null ? _b : "").replace(/\/+$/, "");
|
|
91
93
|
const minioId = `org-minio-${fileId}`;
|
|
92
94
|
const [optimistic] = buildPublishedTileDatasets(
|
|
93
95
|
[{
|