Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Homepage buttons for studies actiosn added #24

Merged
merged 6 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/pages/pegase/home/components/StudiesPagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type StudiesPaginationProps = StdTablePaginationProps;

const StudiesPagination = ({ count, intervalSize, current, onChange }: StudiesPaginationProps) => {
return (
<div className="flex h-9 flex-[1_0_0] items-center justify-end px-4 py-3">
<div className="flex h-9 shrink-0 grow basis-0 items-center justify-end px-4 py-3">
<StdTablePagination count={count} intervalSize={intervalSize} current={current} onChange={onChange} />
</div>
);
Expand Down
194 changes: 73 additions & 121 deletions src/pages/pegase/home/components/StudyTableDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,155 +3,107 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import StdAvatar from '@/components/common/layout/stdAvatar/StdAvatar';
import StdSimpleTable from '@/components/common/data/stdSimpleTable/StdSimpleTable';
import { createColumnHelper } from '@tanstack/react-table';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { StudyDTO } from '@/shared/types/index';
import { StdIconId } from '@/shared/utils/common/mappings/iconMaps';
import StdIcon from '@common/base/stdIcon/StdIcon';
import getStudyTableHeaders from './StudyTableHeaders';
import { addSortColumn } from './StudyTableUtils';
import StudiesPagination from './StudiesPagination';
import StdTagList from '@common/base/StdTagList/StdTagList';
import StdRadioButton from '@/components/common/forms/stdRadioButton/StdRadioButton';
import { RowSelectionState } from '@tanstack/react-table';
import StdButton from '@/components/common/base/stdButton/StdButton';
import { StudyStatus } from '@/shared/types/common/StudyStatus.type';
import { useStudyTableDisplay } from './useStudyTableDisplay';

const columnHelper = createColumnHelper<StudyDTO>();

interface StudyTableDisplayProps {
searchStudy: string | undefined;
projectId?: string;
}

const StudyTableDisplay = ({ searchStudy, projectId }: StudyTableDisplayProps) => {
const { t } = useTranslation();
const [sortBy, setSortBy] = useState<{ [key: string]: 'asc' | 'desc' }>({});
const [sortByState, setSortByState] = useState<{ [key: string]: 'asc' | 'desc' }>({});
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const [sortedColumn, setSortedColumn] = useState<string | null>('status');
const [isHeaderHovered, setIsHeaderHovered] = useState<boolean>(false);

const handleSort = (column: string) => {
const newSortOrder = sortBy[column] === 'asc' ? 'desc' : 'asc';
setSortBy({ [column]: newSortOrder });
const newSortOrder = sortByState[column] === 'asc' ? 'desc' : 'asc';
setSortByState({ [column]: newSortOrder });
setSortedColumn(column);
};
const [sortedColumn, setSortedColumn] = useState<string | null>('status');
const handleHeaderHover = (hovered: boolean) => {
setIsHeaderHovered(hovered);
};

const headers = [
columnHelper.display({
id: 'radioColumn',
header: ({ table }) => (
<StdRadioButton
value="headerRadio"
label="Select All"
checked={table.getIsAllRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
name="headerRadio"
/>
),
cell: ({ row }) => (
<div
onClick={(e) => e.stopPropagation()}
className={`${row.getIsSelected() ? 'block' : 'hidden group-hover:block'}`}
>
<StdRadioButton
value={row.original.id.toString()}
label=""
disabled={!row.getCanSelect()}
checked={row.getIsSelected()}
name={`radio-${row.original.id}`}
/>
</div>
),
}),
const headers = getStudyTableHeaders();
console.log('Original Headers:', headers);

columnHelper.accessor('name', {
header: t('home.@study_name'),
cell: ({ getValue, row }) => {
const status = row.original.status;
const textClass = status === 'GENERATED' ? 'text-primary-900' : 'group-hover:text-green-500';
const sortedHeaders = addSortColumn(
headers,
handleSort,
sortByState,
sortedColumn,
handleHeaderHover,
isHeaderHovered,
);

return <span className={`transition-colors ${textClass}`}>{getValue()}</span>;
},
}),
console.log('Sorted Headers:', sortedHeaders);

columnHelper.accessor('createdBy', {
header: t('home.@user_name'),
cell: ({ getValue }: { getValue: () => string }) => (
<StdAvatar size="s" backgroundColor="gray" fullname={getValue()} initials={getValue().substring(0, 2)} />
),
}),
columnHelper.accessor('project', { header: t('home.@project') }),
columnHelper.accessor('status', { header: t('home.@status') }),
columnHelper.accessor('horizon', { header: t('home.@horizon') }),
columnHelper.accessor('keywords', {
header: 'keywords',
minSize: 500,
size: 500,
cell: ({ getValue, row }) => (
<div className="flex h-3 w-32">
<StdTagList id={`pegase-tags-${row.id}`} tags={getValue()} />
</div>
),
}),
columnHelper.accessor('creationDate', { header: t('home.@creation_date') }),
];
const { rows, count, intervalSize, current, setPage } = useStudyTableDisplay({
searchStudy,
projectId,
sortBy: sortByState,
});

const [isHeaderHovered, setIsHeaderHovered] = useState<boolean>(false);
const selectedRowId = Object.keys(rowSelection)[0];

const handleHeaderHover = (hovered: boolean) => {
setIsHeaderHovered(hovered);
};
const selectedStatus = rows[Number.parseInt(selectedRowId || '-1')]?.status?.toUpperCase();

function addSortColumn(headers: any[]) {
return headers.map((column) => {
const isSortable = column.accessorKey !== 'keywords' && column.id !== 'radioColumn';
return {
...column,
header: (
<div
className={`flex items-center ${isSortable ? 'cursor-pointer' : ''} header-container group`}
onMouseEnter={() => isSortable && handleHeaderHover(true)}
onMouseLeave={() => isSortable && handleHeaderHover(false)}
onClick={() => {
if (isSortable) {
handleHeaderHover(false);
handleSort(column.accessorKey as string);
}
}}
>
<div>{column.header}</div>
{isSortable && (
<div>
{sortBy[column.accessorKey as string] && sortedColumn === column.accessorKey ? (
sortBy[column.accessorKey as string] === 'asc' ? (
<span className="font-bold text-primary-600">
<StdIcon name={StdIconId.ArrowUpwardAlt} />
</span>
) : (
<span className="font-bold text-primary-600">
<StdIcon name={StdIconId.ArrowDownwardAlt} />
</span>
)
) : (
<span
className={`text-primary-900 ${isHeaderHovered ? 'opacity-100' : 'opacity-0'} transition-opacity duration-100`}
>
<StdIcon name={StdIconId.ArrowUpwardAlt} />
</span>
)}
</div>
)}
</div>
),
};
});
}
const { rows, count, intervalSize, current, setPage } = useStudyTableDisplay({ searchStudy, projectId, sortBy });
const isDuplicateActive = selectedStatus === StudyStatus.GENERATED;
const isDeleteActive = selectedStatus === StudyStatus.ERROR || selectedStatus === StudyStatus.IN_PROGRESS;

return (
<div>
<div className="flex-1">
<StdSimpleTable columns={addSortColumn(headers)} data={rows as StudyDTO[]} enableRowSelection={true} />
<StdSimpleTable
columns={sortedHeaders}
data={rows as StudyDTO[]}
enableRowSelection={true}
state={{
rowSelection,
}}
onRowSelectionChange={(
updaterOrValue: RowSelectionState | ((oldState: RowSelectionState) => RowSelectionState),
) => {
if (typeof updaterOrValue === 'function') {
setRowSelection((prev: RowSelectionState) => updaterOrValue(prev));
} else {
setRowSelection(updaterOrValue);
}
}}
/>
</div>
<div className="flex h-[60px] items-center justify-between bg-gray-200 px-[32px]">
<div className="flex h-8 items-center justify-between bg-gray-200 px-4">
<div className="flex gap-2">
{selectedRowId !== undefined ? (
<>
<StdButton
label="Duplicate"
onClick={() => console.log('duplicate')}
variant="outlined"
disabled={!isDuplicateActive}
/>
<StdButton
label="Delete"
onClick={() => console.log('Delete')}
variant="outlined"
color="danger"
disabled={!isDeleteActive}
/>
</>
) : (
<StdButton label="NewStudy" onClick={() => console.log('NewStudy')} />
)}
</div>
<StudiesPagination count={count} intervalSize={intervalSize} current={current} onChange={setPage} />
</div>
</div>
Expand Down
81 changes: 81 additions & 0 deletions src/pages/pegase/home/components/StudyTableHeaders.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import StdTagList from '@/components/common/base/StdTagList/StdTagList';
import StdRadioButton from '@/components/common/forms/stdRadioButton/StdRadioButton';
import StdAvatar from '@/components/common/layout/stdAvatar/StdAvatar';
import { StudyStatus } from '@/shared/types/common/StudyStatus.type';
import { StudyDTO } from '@/shared/types/pegase/study';
import { createColumnHelper } from '@tanstack/react-table';
import { useTranslation } from 'react-i18next';

const columnHelper = createColumnHelper<StudyDTO>();

const getStudyTableHeaders = () => {
const { t } = useTranslation();
return [
columnHelper.display({
id: 'radioColumn',
header: () => <></>,
cell: ({ row }) => (
<div className={`${row.getIsSelected() ? 'block' : 'hidden group-hover:block'}`}>
<StdRadioButton
value={row.original.id.toString()}
label=""
disabled={!row.getCanSelect()}
checked={row.getIsSelected()}
name={`radio-${row.original.id}`}
/>
</div>
),
}),

columnHelper.accessor('name', {
header: t('home.@study_name'),
cell: ({ getValue, row }) => {
const status = row.original.status;
const textClass = status === StudyStatus.GENERATED ? 'text-primary-900' : 'group-hover:text-green-500';
return <span className={`transition-colors ${textClass}`}>{getValue()}</span>;
},
}),

columnHelper.accessor('createdBy', {
header: t('home.@user_name'),
cell: ({ getValue }) => (
<StdAvatar size="s" backgroundColor="gray" fullname={getValue()} initials={getValue().substring(0, 2)} />
),
}),

columnHelper.accessor('project', {
header: t('home.@project'),
}),

columnHelper.accessor('status', {
header: t('home.@status'),
}),

columnHelper.accessor('horizon', {
header: t('home.@horizon'),
}),

columnHelper.accessor('keywords', {
header: t('home.@keywords'),
minSize: 500,
size: 500,
cell: ({ getValue, row }) => (
<div className="flex h-3 w-32">
<StdTagList id={`pegase-tags-${row.id}`} tags={getValue()} />
</div>
),
}),

columnHelper.accessor('creationDate', {
header: t('home.@creation_date'),
}),
];
};

export default getStudyTableHeaders;
62 changes: 62 additions & 0 deletions src/pages/pegase/home/components/StudyTableUtils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import StdIcon from '@/components/common/base/stdIcon/StdIcon';
import { StdIconId } from '@/shared/utils/common/mappings/iconMaps';

export function addSortColumn(
headers: any[],
handleSort: (column: string) => void,
sortBy: { [key: string]: 'asc' | 'desc' },
sortedColumn: string | null,
handleHeaderHover: (hovered: boolean) => void,
isHeaderHovered: boolean,
) {
return headers.map((column) => {
const isSortable = column.accessorKey !== 'keywords' && column.id !== 'radioColumn';
return {
...column,
header: (
<div
className={`flex items-center ${isSortable ? 'cursor-pointer' : ''} header-container group`}
onMouseEnter={() => isSortable && handleHeaderHover(true)}
onMouseLeave={() => isSortable && handleHeaderHover(false)}
onClick={() => {
if (isSortable) {
handleHeaderHover(false);
handleSort(column.accessorKey as string);
}
}}
>
<div>{column.header}</div>
{isSortable && (
<div>
{sortBy[column.accessorKey as string] && sortedColumn === column.accessorKey ? (
sortBy[column.accessorKey as string] === 'asc' ? (
<span className="font-bold text-primary-600">
<StdIcon name={StdIconId.ArrowUpwardAlt} />
</span>
) : (
<span className="font-bold text-primary-600">
<StdIcon name={StdIconId.ArrowDownwardAlt} />
</span>
)
) : (
<span
className={`text-primary-900 ${
isHeaderHovered ? 'opacity-100' : 'opacity-0'
} transition-opacity duration-100`}
>
<StdIcon name={StdIconId.ArrowUpwardAlt} />
</span>
)}
</div>
)}
</div>
),
};
});
}
13 changes: 13 additions & 0 deletions src/shared/types/common/StudyStatus.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

export enum StudyStatus {
IN_PROGRESS = 'IN_PROGRESS',
GENERATED = 'GENERATED',
ERROR = 'ERROR',
CLOSED = 'CLOSED',
DELETED = 'DELETED',
}
Loading
Loading