Skip to content

Commit

Permalink
feat: untokenized Units WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
wwills2 committed Aug 19, 2024
1 parent 7e38947 commit 6522d02
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 58 deletions.
81 changes: 81 additions & 0 deletions src/renderer/components/blocks/tabs/UntokenizedUnitsTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { FormattedMessage } from 'react-intl';
import { ProjectModal, ProjectsListTable, SkeletonTable } from '@/components';

Check failure on line 2 in src/renderer/components/blocks/tabs/UntokenizedUnitsTab.tsx

View workflow job for this annotation

GitHub Actions / Build Windows Installer

Module '"@/components"' has no exported member 'ProjectModal'.

Check failure on line 2 in src/renderer/components/blocks/tabs/UntokenizedUnitsTab.tsx

View workflow job for this annotation

GitHub Actions / Build CADT UI Web App

Module '"@/components"' has no exported member 'ProjectModal'.

Check failure on line 2 in src/renderer/components/blocks/tabs/UntokenizedUnitsTab.tsx

View workflow job for this annotation

GitHub Actions / Build Linux Installer

Module '"@/components"' has no exported member 'ProjectModal'.

Check failure on line 2 in src/renderer/components/blocks/tabs/UntokenizedUnitsTab.tsx

View workflow job for this annotation

GitHub Actions / Build Mac Installer

Module '"@/components"' has no exported member 'ProjectModal'.
import React, { useCallback, useEffect } from 'react';
import { useGetProjectsQuery } from '@/api';
import { useColumnOrderHandler, useQueryParamState, useWildCardUrlHash } from '@/hooks';
import { debounce } from 'lodash';

interface PageTabProps {
orgUid: string;
search: string;
order: string;
setOrder: (order: string) => void;
setIsLoading: (isLoading: boolean) => void;
}

const UntokenizedUnitsTab: React.FC<PageTabProps> = ({
orgUid,
search,
order,
setOrder,
setIsLoading,
}: PageTabProps) => {
const [currentPage, setCurrentPage] = useQueryParamState('page', '1');
const handleSetOrder = useColumnOrderHandler(order, setOrder);
const [projectDetailsFragment, projectDetailsModalActive, setProjectModalActive] = useWildCardUrlHash('project');
const {
data: projectsData,
isLoading: projectsLoading,
error: projectsError,
} = useGetProjectsQuery({ page: Number(currentPage), orgUid, search, order });

useEffect(() => {
setIsLoading(projectsLoading);
}, [projectsLoading, setIsLoading]);

const handlePageChange = useCallback(
debounce((page) => setCurrentPage(page), 800),
[setCurrentPage],
);

if (projectsLoading) {
return <SkeletonTable />;
}

if (projectsError) {
return <FormattedMessage id={'unable-to-load-contents'} />;
}

if (!projectsData) {
return <FormattedMessage id={'no-records-found'} />;
}

return (
<>
{projectsLoading ? (
<SkeletonTable />
) : (
<ProjectsListTable
data={projectsData?.data || []}
rowActions="edit"
isLoading={projectsLoading}
currentPage={Number(currentPage)}
onPageChange={handlePageChange}
onRowClick={(row) => setProjectModalActive(true, row.warehouseProjectId)}
setOrder={handleSetOrder}
order={order}
totalPages={projectsData.pageCount}
totalCount={projectsData.pageCount < 10 ? projectsData.data.length : projectsData.pageCount * 10}
/>
)}
{projectDetailsModalActive && (
<ProjectModal
onClose={() => setProjectModalActive(false)}
warehouseProjectId={projectDetailsFragment.replace('project-', '')}
/>
)}
</>
);
};

export { UntokenizedUnitsTab };
2 changes: 1 addition & 1 deletion src/renderer/components/blocks/tabs/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export {};
export * from './UntokenizedUnitsTab';
28 changes: 28 additions & 0 deletions src/renderer/components/blocks/widgets/SearchBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { TextInput } from '@/components';
import { IoSearchSharp } from 'react-icons/io5';
import React from 'react';
import { IntlShape, useIntl } from 'react-intl';

interface SearchBoxProps {
defaultValue: string;
onChange: (event: any) => void;
}

const SearchBox: React.FC<SearchBoxProps> = ({ defaultValue, onChange }) => {
const intl: IntlShape = useIntl();

return (
<div className="flex justify-center items-center w-full md:max-w-md">
<TextInput
type="text"
icon={IoSearchSharp}
defaultValue={defaultValue || ''}
onChange={onChange}
placeholder={intl.formatMessage({ id: 'search' })}
className="w-full"
/>
</div>
);
};

export { SearchBox };
1 change: 1 addition & 0 deletions src/renderer/components/blocks/widgets/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './ThemeModeSelector';
export * from './SearchBox';
192 changes: 140 additions & 52 deletions src/renderer/pages/ListPageSample.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,157 @@
import React, { useCallback } from 'react';
import { useGetProjectsQuery } from '@/api';
import { useColumnOrderHandler, useQueryParamState, useWildCardUrlHash } from '@/hooks';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useQueryParamState, useUrlHash } from '@/hooks';
import { debounce } from 'lodash';
import { IndeterminateProgressOverlay, ProjectsListTable, SampleDeepLinkedModal, SkeletonTable } from '@/components';
import {
Button,
UntokenizedUnitsTab,
ComponentCenteredSpinner,
IndeterminateProgressOverlay,
SearchBox,
Tabs,
} from '@/components';
import { FormattedMessage } from 'react-intl';
import { Organization } from '@/schemas/Organization.schema';
import { useNavigate } from 'react-router-dom';
import { useGetOrganizationsListQuery } from '@/api';

Check failure on line 15 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Windows Installer

Module '"@/api"' has no exported member 'useGetOrganizationsListQuery'.

Check failure on line 15 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build CADT UI Web App

Module '"@/api"' has no exported member 'useGetOrganizationsListQuery'.

Check failure on line 15 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Linux Installer

Module '"@/api"' has no exported member 'useGetOrganizationsListQuery'.

Check failure on line 15 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Mac Installer

Module '"@/api"' has no exported member 'useGetOrganizationsListQuery'.
// @ts-ignore
import { useGetStagedProjectsQuery } from '@/api/cadt/v1/staging';

const ListPageSample: React.FC = () => {
const [currentPage, setCurrentPage] = useQueryParamState('page', '1');
const [orgUid /* set func here */] = useQueryParamState('orgUid', undefined);
const [search /* set func here */] = useQueryParamState('search', undefined);
const [order, setOrder] = useQueryParamState('order', undefined);
const handleSetOrder = useColumnOrderHandler(order, setOrder);
const [projectDetailsFragment, projectDetailsModalActive, setProjectModalActive] = useWildCardUrlHash('project');
enum TabTypes {
TOKENIZED,
UNTOKENIZED,
}

const {
data: projectsData,
isLoading: projectsLoading,
isFetching: projectsFetching,
error: projectsError,
} = useGetProjectsQuery({ page: Number(currentPage), orgUid, search, order });
interface ProcessedStagingData {
staged: any[];
pending: any[];
failed: any[];
transfer: any;
}

const handlePageChange = useCallback(
debounce((page) => setCurrentPage(page), 800),
[setCurrentPage],
const MyProjectsPage: React.FC = () => {
const navigate = useNavigate();
const [orgUid, setOrgUid] = useQueryParamState('orgUid', undefined);
const [search, setSearch] = useQueryParamState('search', undefined);
const [order, setOrder] = useQueryParamState('order', undefined);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [projectStagedSuccess, setProjectStagedSuccess] = useUrlHash('success-stage-project');

Check failure on line 37 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Windows Installer

'projectStagedSuccess' is declared but its value is never read.

Check failure on line 37 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Windows Installer

'setProjectStagedSuccess' is declared but its value is never read.

Check failure on line 37 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build CADT UI Web App

'projectStagedSuccess' is declared but its value is never read.

Check failure on line 37 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build CADT UI Web App

'setProjectStagedSuccess' is declared but its value is never read.

Check failure on line 37 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Linux Installer

'projectStagedSuccess' is declared but its value is never read.

Check failure on line 37 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Linux Installer

'setProjectStagedSuccess' is declared but its value is never read.

Check failure on line 37 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Mac Installer

'projectStagedSuccess' is declared but its value is never read.

Check failure on line 37 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Mac Installer

'setProjectStagedSuccess' is declared but its value is never read.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [commitModalActive, setCommitModalActive] = useUrlHash('commit-staged-items');

Check failure on line 39 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Windows Installer

'commitModalActive' is declared but its value is never read.

Check failure on line 39 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build CADT UI Web App

'commitModalActive' is declared but its value is never read.

Check failure on line 39 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Linux Installer

'commitModalActive' is declared but its value is never read.

Check failure on line 39 in src/renderer/pages/ListPageSample.tsx

View workflow job for this annotation

GitHub Actions / Build Mac Installer

'commitModalActive' is declared but its value is never read.
const [, setCreateProjectModalActive] = useUrlHash('create-project');
const [activeTab, setActiveTab] = useState<TabTypes>(TabTypes.UNTOKENIZED);
const [committedDataLoading, setCommittedDataLoading] = useState<boolean>(false);
const { data: unprocessedStagedProjects, isLoading: stagingDataLoading } = useGetStagedProjectsQuery();
const { data: organizationsListData, isLoading: organizationsListLoading } = useGetOrganizationsListQuery();
const myOrganization = useMemo<Organization | undefined>(
() => organizationsListData?.find((org: Organization) => org.isHome),
[organizationsListData],
);

if (projectsLoading) {
return <SkeletonTable />;
}
const processedStagingData: ProcessedStagingData = useMemo<ProcessedStagingData>(() => {
const data: ProcessedStagingData = { staged: [], pending: [], failed: [], transfer: undefined };
if (unprocessedStagedProjects?.forEach) {
unprocessedStagedProjects.forEach((stagedProject: any) => {
if (stagedProject?.table === 'Projects') {
if (!stagedProject.commited && !stagedProject.failedCommit && !stagedProject.isTransfer) {
data.staged.push(stagedProject);
} else if (stagedProject.commited && !stagedProject.failedCommit && !stagedProject.isTransfer) {
data.pending.push(stagedProject);
} else if (!stagedProject.commited && stagedProject.failedCommit && !stagedProject.isTransfer) {
data.failed.push(stagedProject);
} else if (stagedProject.commited && stagedProject.isTransfer) {
data.transfer = stagedProject;
}
}
});
}
return data;
}, [unprocessedStagedProjects]);

if (projectsError) {
return <FormattedMessage id={'unable-to-load-contents'} />;
}
const contentsLoading = useMemo<boolean>(() => {
return committedDataLoading || stagingDataLoading;
}, [committedDataLoading, stagingDataLoading]);

useEffect(() => {
if (myOrganization) {
setOrgUid(myOrganization.orgUid);
}
}, [myOrganization, myOrganization?.orgUid, organizationsListData, setOrgUid]);

useEffect(() => {
if (!myOrganization && !organizationsListLoading) {
navigate('/');
}
}, [myOrganization, navigate, organizationsListLoading]);

const handleSearchChange = useCallback(
debounce((event: any) => {
setSearch(event.target.value);
}, 800),
[setSearch, debounce],
);

if (!projectsData) {
return <FormattedMessage id={'no-records-found'} />;
if (!myOrganization || organizationsListLoading) {
return <ComponentCenteredSpinner />;
}

return (
<>
{projectsFetching && <IndeterminateProgressOverlay />}
{projectsLoading ? (
<SkeletonTable />
) : (
<ProjectsListTable
data={projectsData?.data || []}
rowActions="transfer"
isLoading={projectsLoading}
currentPage={Number(currentPage)}
onPageChange={handlePageChange}
onRowClick={(row) => setProjectModalActive(true, row.warehouseProjectId)}
setOrder={handleSetOrder}
order={order}
totalPages={projectsData.pageCount}
totalCount={projectsData.pageCount < 10 ? projectsData.data.length : projectsData.pageCount * 10}
/>
)}
{projectDetailsModalActive && (
<SampleDeepLinkedModal
onClose={() => setProjectModalActive(false)}
urlFragmentDerivedData={projectDetailsFragment.replace('project-', '')}
/>
)}
<div className="pt-2 pl-2 pr-2 h-full">
{contentsLoading && <IndeterminateProgressOverlay />}
<div className="flex flex-col md:flex-row gap-6 my-2.5 relative z-30 items-center h-auto">
{activeTab === TabTypes.UNTOKENIZED && (
<>
<Button disabled={contentsLoading} onClick={() => setCreateProjectModalActive(true)}>
<FormattedMessage id="create-project" />
</Button>
<SearchBox defaultValue={search} onChange={handleSearchChange} />
</>
)}
{activeTab === TabTypes.TOKENIZED && (
<>
<Button
disabled={contentsLoading || !processedStagingData.staged.length}
onClick={() => setCommitModalActive(true)}
>
<FormattedMessage id="commit" />
</Button>
</>
)}
</div>
<div className="h-13">
<Tabs onActiveTabChange={(tab: TabTypes) => setActiveTab(tab)}>
<Tabs.Item
title={
<p className="capitalize">
<FormattedMessage id="untokenized-units" />
</p>
}
/>
<Tabs.Item
title={
<p className="capitalize">
<FormattedMessage id="tokenized-units" />
{' (' + String(processedStagingData.staged.length + ') ')}
</p>
}
/>
</Tabs>
</div>
<div id="tabs content">
{activeTab === TabTypes.UNTOKENIZED && (
<UntokenizedUnitsTab
orgUid={orgUid}
search={search}
order={order}
setOrder={setOrder}
setIsLoading={setCommittedDataLoading}
/>
)}
{activeTab === TabTypes.TOKENIZED && <div>TODO: tokenized units tab</div>}
</div>
</div>
</>
);
};

export { ListPageSample };
export { MyProjectsPage };
6 changes: 3 additions & 3 deletions src/renderer/routes/AppNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const AppNavigator: React.FC = () => {
loader={({ params }) => redirect(params['*'] || '/')}
/>
<Route path="" element={<Template />}>
<Route path="/" element={<Navigate to={ROUTES.PROJECTS_LIST} />} />
<Route path={ROUTES.PROJECTS_LIST} element={<Pages.ListPageSample />} />
<Route path="*" element={<Navigate replace to={ROUTES.PROJECTS_LIST} />} />
<Route path="/" element={<Navigate to={ROUTES.CREATE_TOKENS} />} />
<Route path={ROUTES.CREATE_TOKENS} element={<Pages.ListPageSample />} />

Check failure on line 18 in src/renderer/routes/AppNavigator.tsx

View workflow job for this annotation

GitHub Actions / Build Windows Installer

Property 'ListPageSample' does not exist on type 'typeof import("D:/a/Climate-Tokenization-Engine-UI/Climate-Tokenization-Engine-UI/src/renderer/pages/index")'.

Check failure on line 18 in src/renderer/routes/AppNavigator.tsx

View workflow job for this annotation

GitHub Actions / Build CADT UI Web App

Property 'ListPageSample' does not exist on type 'typeof import("/home/runner/work/Climate-Tokenization-Engine-UI/Climate-Tokenization-Engine-UI/src/renderer/pages/index")'.

Check failure on line 18 in src/renderer/routes/AppNavigator.tsx

View workflow job for this annotation

GitHub Actions / Build Linux Installer

Property 'ListPageSample' does not exist on type 'typeof import("/home/runner/work/Climate-Tokenization-Engine-UI/Climate-Tokenization-Engine-UI/src/renderer/pages/index")'.

Check failure on line 18 in src/renderer/routes/AppNavigator.tsx

View workflow job for this annotation

GitHub Actions / Build Mac Installer

Property 'ListPageSample' does not exist on type 'typeof import("/Users/runner/work/Climate-Tokenization-Engine-UI/Climate-Tokenization-Engine-UI/src/renderer/pages/index")'.
<Route path="*" element={<Navigate replace to={ROUTES.CREATE_TOKENS} />} />
</Route>
</Routes>
{/* app-wide blocking modals go below this comment*/}
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/routes/route-constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export default {
PROJECTS_LIST: '/projects',
CREATE_TOKENS: '/create-tokens',
REVERT_TOKENS: '/revert-tokens',
};
4 changes: 3 additions & 1 deletion src/renderer/translations/tokens/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@
"server-address": "Server Address",
"api-key": "API Key",
"connect": "connect",
"unable-to-load-contents": "unable to load contents"
"unable-to-load-contents": "unable to load contents",
"tokenized-units": "tokenized units",
"untokenized-units": "untokenized units"
}

0 comments on commit 6522d02

Please sign in to comment.