diff --git a/src/renderer/components/blocks/layout/LeftNav.tsx b/src/renderer/components/blocks/layout/LeftNav.tsx index f2f4433b..8cc500f1 100644 --- a/src/renderer/components/blocks/layout/LeftNav.tsx +++ b/src/renderer/components/blocks/layout/LeftNav.tsx @@ -42,6 +42,24 @@ const LeftNav = () => { > +
handleNavigation(ROUTES.UNITS_LIST)} + className={`cursor-pointer p-3 ${isActive(ROUTES.UNITS_LIST) ? 'bg-gray-200 dark:bg-gray-600 text-gray-800 dark:text-white' : 'text-gray-700 dark:text-gray-300'} hover:bg-gray-300 dark:hover:bg-gray-700 rounded-md text-lg font-semibold`} + > + +
+
handleNavigation(ROUTES.AUDIT)} + className={`cursor-pointer p-3 ${isActive(ROUTES.AUDIT) ? 'bg-gray-200 dark:bg-gray-600 text-gray-800 dark:text-white' : 'text-gray-700 dark:text-gray-300'} hover:bg-gray-300 dark:hover:bg-gray-700 rounded-md text-lg font-semibold`} + > + +
+
handleNavigation(ROUTES.GLOSSARY)} + className={`cursor-pointer p-3 ${isActive(ROUTES.GLOSSARY) ? 'bg-gray-200 dark:bg-gray-600 text-gray-800 dark:text-white' : 'text-gray-700 dark:text-gray-300'} hover:bg-gray-300 dark:hover:bg-gray-700 rounded-md text-lg font-semibold`} + > + +
{/* Additional mobile navigation items here */} @@ -69,7 +87,7 @@ const LeftNav = () => { active={isActive(ROUTES.AUDIT)} onClick={() => navigate(ROUTES.AUDIT)} > - + = ({ orgUid }) => { + const [showToast, setShowToast] = useState(false); + const [toastVisible, setToastVisible] = useState(false); + const [toastMessage, setToastMessage] = useState(''); + + useEffect(() => { + let timeoutId: NodeJS.Timeout; + + if (showToast) { + setToastVisible(true); + timeoutId = setTimeout(() => setShowToast(false), 3000); + } else if (!showToast && toastVisible) { + timeoutId = setTimeout(() => setToastVisible(false), 300); + } + + return () => clearTimeout(timeoutId); + }, [showToast, toastVisible]); + + const handleCopyToClipboard = () => { + navigator.clipboard + .writeText(orgUid) + .then(() => { + setToastMessage('Org UID copied to clipboard!'); + setShowToast(true); + }) + .catch((err) => { + console.error('Failed to copy Org UID: ', err); + setToastMessage('Failed to copy Org UID.'); + setShowToast(true); + }); + }; + + if (!orgUid) { + return null; + } + + return ( + <> + {toastVisible && ( +
+ + {toastMessage} + +
+ )} + + + {orgUid} + + + + ); +}; + +export { OrgUidBadge }; diff --git a/src/renderer/components/blocks/widgets/OrganizationSelector.tsx b/src/renderer/components/blocks/widgets/OrganizationSelector.tsx index d79e45ce..2a18ef3b 100644 --- a/src/renderer/components/blocks/widgets/OrganizationSelector.tsx +++ b/src/renderer/components/blocks/widgets/OrganizationSelector.tsx @@ -5,9 +5,10 @@ import { Dropdown, SyncIndicator } from '@/components'; interface OrganizationSelectorProps { onSelect: (organization: any | undefined) => void; defaultOrgUid: string | undefined; + noSelectionLabel?: string } -const OrganizationSelector: React.FC = ({ onSelect, defaultOrgUid }) => { +const OrganizationSelector: React.FC = ({ onSelect, defaultOrgUid, noSelectionLabel = 'Select Organization' }) => { const { data: organizations, error, isLoading } = useGetOrganizationsListQuery({}); const [selectedOrganization, setSelectedOrganization] = useState(undefined); @@ -36,7 +37,7 @@ const OrganizationSelector: React.FC = ({ onSelect, d }; return ( - + handleSelect(undefined)}>All Organizations {organizations.map((organization) => ( = ({ detailed, orgUid }) => { } return ( -
+
{detailed && ( - <> +
{isSynced ? 'Synced' : 'Syncing...'} {!isSynced && ( - // Made "sync remaining" more subtle with lighter color and smaller font - ({syncRemaining} remaining) + {syncRemaining} remaining )} - +
)}
); diff --git a/src/renderer/components/blocks/widgets/index.ts b/src/renderer/components/blocks/widgets/index.ts index 0ac7de71..ff359cac 100644 --- a/src/renderer/components/blocks/widgets/index.ts +++ b/src/renderer/components/blocks/widgets/index.ts @@ -1,3 +1,4 @@ export * from './SearchBox'; export * from './OrganizationSelector'; -export * from './SyncIndicator'; \ No newline at end of file +export * from './SyncIndicator'; +export * from './OrgUidBadge'; \ No newline at end of file diff --git a/src/renderer/pages/Audit/AuditPage.tsx b/src/renderer/pages/Audit/AuditPage.tsx index 563de953..1d8e62ab 100644 --- a/src/renderer/pages/Audit/AuditPage.tsx +++ b/src/renderer/pages/Audit/AuditPage.tsx @@ -8,6 +8,7 @@ import { SkeletonTable, AuditsTable, SearchBox, + SyncIndicator } from '@/components'; import {FormattedMessage} from "react-intl"; @@ -92,6 +93,7 @@ const AuditPage: React.FC = () => {
+
<> {auditLoading ? ( diff --git a/src/renderer/pages/ProjectsList/ProjectsListPage.tsx b/src/renderer/pages/ProjectsList/ProjectsListPage.tsx index 015c1cea..3c3a30dd 100644 --- a/src/renderer/pages/ProjectsList/ProjectsListPage.tsx +++ b/src/renderer/pages/ProjectsList/ProjectsListPage.tsx @@ -1,16 +1,17 @@ import React, { useCallback } from 'react'; import { useGetProjectsQuery } from '@/api'; import { useQueryParamState, useColumnOrderHandler } from '@/hooks'; -import {debounce, DebouncedFunc} from 'lodash'; +import { debounce, DebouncedFunc } from 'lodash'; import { OrganizationSelector, IndeterminateProgressOverlay, SkeletonTable, ProjectsListTable, SearchBox, - SyncIndicator + SyncIndicator, + OrgUidBadge, } from '@/components'; -import {FormattedMessage} from "react-intl"; +import { FormattedMessage } from 'react-intl'; const ProjectsListPage: React.FC = () => { const [currentPage, setCurrentPage] = useQueryParamState('page', '1'); @@ -50,20 +51,25 @@ const ProjectsListPage: React.FC = () => { } if (projectsError) { - return ; + return ; } - if (!projectsData){ - return ; + if (!projectsData) { + return ; } return ( <> {projectsFetching && } -
+
- + +
{projectsLoading ? ( diff --git a/src/renderer/pages/UnitsList/UnitsListPage.tsx b/src/renderer/pages/UnitsList/UnitsListPage.tsx index a06a8125..ffe1d7f8 100644 --- a/src/renderer/pages/UnitsList/UnitsListPage.tsx +++ b/src/renderer/pages/UnitsList/UnitsListPage.tsx @@ -1,16 +1,17 @@ import React, { useCallback } from 'react'; import { useGetUnitsQuery } from '@/api'; import { useQueryParamState, useColumnOrderHandler } from '@/hooks'; -import {debounce, DebouncedFunc} from 'lodash'; +import { debounce, DebouncedFunc } from 'lodash'; import { OrganizationSelector, IndeterminateProgressOverlay, SkeletonTable, SearchBox, UnitsListTable, - SyncIndicator + SyncIndicator, + OrgUidBadge, } from '@/components'; -import {FormattedMessage} from "react-intl"; +import { FormattedMessage } from 'react-intl'; const UnitsListPage: React.FC = () => { const [currentPage, setCurrentPage] = useQueryParamState('page', '1'); @@ -50,11 +51,11 @@ const UnitsListPage: React.FC = () => { } if (unitsError) { - return ; + return ; } - if (!unitsData){ - return ; + if (!unitsData) { + return ; } return ( @@ -62,8 +63,13 @@ const UnitsListPage: React.FC = () => { {unitsFetching && }
- + +
{unitsLoading ? ( diff --git a/src/renderer/routes/AppNavigator.tsx b/src/renderer/routes/AppNavigator.tsx index edb56a54..0ec2c39d 100644 --- a/src/renderer/routes/AppNavigator.tsx +++ b/src/renderer/routes/AppNavigator.tsx @@ -23,6 +23,7 @@ const AppNavigator: React.FC = () => { } /> } /> } /> + } /> } /> } /> diff --git a/src/renderer/translations/tokens/en-US.json b/src/renderer/translations/tokens/en-US.json index acb84668..eeaf1caf 100644 --- a/src/renderer/translations/tokens/en-US.json +++ b/src/renderer/translations/tokens/en-US.json @@ -28,7 +28,6 @@ "covered-by-ndc": "Covered By Ndc", "project-status": "Project Status", "unit-metric": "Unit Metric", - "validation-body": "Validation Body", "table": "Table", "timestamp": "Timestamp", "type": "Type", @@ -36,7 +35,7 @@ "author": "Author", "comment": "Comment", "please-select-an-organization-to-view-audit-data": "Please select an organization to view audit data", - "audits": "Audits", + "audit": "Audit", "validation-body": "Validation Body", "glossary": "Glossary", "term": "Term",