Skip to content

Commit

Permalink
Merge pull request #23 from concord-consortium/186024265-add-table-re…
Browse files Browse the repository at this point in the history
…order

feat: Added re-order and move attributes [PT-186024265] [PT-186024290]
  • Loading branch information
dougmartin committed Oct 3, 2023
2 parents 44a47c5 + 73b4f8d commit c3dbebb
Show file tree
Hide file tree
Showing 10 changed files with 380 additions and 72 deletions.
2 changes: 2 additions & 0 deletions src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ function App() {
handleSelectDataSet={handleSelectDataSet}
updateInteractiveState={updateInteractiveState}
handleShowComponent={handleShowComponent}
handleUpdateAttributePosition={handleUpdateAttributePosition}
handleSetCollections={handleSetCollections}
/>
);

Expand Down
105 changes: 105 additions & 0 deletions src/components/draggable-table-tags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from "react";
import { useDraggableTableContext, Side } from "../hooks/useDraggableTable";

import css from "./tables.scss";

const border = "5px solid #FBF719";
const borderLeft = border;
const borderRight = border;

const getStyle = (id: string, dragOverId?: string, dragSide?: Side) => {
return id === dragOverId ? (dragSide === "left" ? {borderLeft} : {borderRight}) : {};
};

const getIdAndStyle = (collectionId: number, attrTitle: string, dragOverId?: string, dragSide?: Side)
: {id: string, style: React.CSSProperties} => {
const id = `${collectionId}-${attrTitle}`;
const style = getStyle(id, dragOverId, dragSide);
return { id, style };
};

interface DraggagleTableHeaderProps {
collectionId: number;
attrTitle: string;
colSpan?: number;
}

export const DraggagleTableHeader: React.FC<DraggagleTableHeaderProps> = ({collectionId, attrTitle, children}) => {
const {dragOverId, dragSide, handleDragStart, handleDragOver, handleOnDrop, handleDragEnter,
handleDragLeave} = useDraggableTableContext();
const {id, style} = getIdAndStyle(collectionId, attrTitle, dragOverId, dragSide);

return (
<th
data-id={id}
style={style}
draggable={true}
className={css.draggable}
onDragStart={handleDragStart}
onDragOver={handleDragOver}
onDrop={handleOnDrop}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
>
{children}
</th>
);
};

interface DroppableTableHeaderProps {
collectionId: number;
}

export const DroppableTableHeader: React.FC<DroppableTableHeaderProps> = ({collectionId, children}) => {
const {dragOverId, handleDragOver, handleOnDrop, handleDragEnter,
handleDragLeave} = useDraggableTableContext();

const id = `${collectionId}`;
const style = getStyle(id, dragOverId, "left");

return (
<th
data-id={id}
style={style}
onDragOver={handleDragOver}
onDrop={handleOnDrop}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
>
{children}
</th>
);
};

interface DraggagleTableDataProps {
collectionId: number;
attrTitle: string;
style?: React.CSSProperties;
}

export const DraggagleTableData: React.FC<DraggagleTableDataProps> = ({collectionId, attrTitle, children}) => {
const {dragOverId, dragSide} = useDraggableTableContext();
const {style} = getIdAndStyle(collectionId, attrTitle, dragOverId, dragSide);

return (
<td style={style}>
{children}
</td>
);
};

interface DroppableTableDataProps {
collectionId: number;
style?: React.CSSProperties;
}

export const DroppableTableData: React.FC<DroppableTableDataProps> = ({collectionId, style, children}) => {
const {dragOverId, dragSide} = useDraggableTableContext();
const dragStyle = getStyle(`${collectionId}`, dragOverId, dragSide);

return (
<td style={{...dragStyle, ...style}}>
{children}
</td>
);
};
25 changes: 21 additions & 4 deletions src/components/flat-table.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";
import { ITableProps } from "../types";
import { ITableProps, IValues } from "../types";
import { DraggagleTableHeader } from "./draggable-table-tags";

import css from "./tables.scss";

Expand All @@ -12,6 +13,15 @@ export const FlatTable = (props: IFlatProps) => {
const collection = collections[0];
const {className} = collectionClasses[0];

const titles = collection.attrs.map(attr => attr.title);
const orderedItems = items.map(item => {
const orderedItem: IValues = {};
titles.forEach(title => {
orderedItem[title] = item[title];
});
return orderedItem;
});

return (
<table className={`${css.mainTable} ${css.flatTable} ${css[className]}}`}>
<tbody>
Expand All @@ -23,11 +33,18 @@ export const FlatTable = (props: IFlatProps) => {
<th colSpan={items.length}>{collections[0].title}</th>
</tr>}
<tr>
{collection.attrs.map((attr: any) => <th key={attr.title}>{attr.title}</th>)}
{collection.attrs.map((attr: any) =>
<DraggagleTableHeader
key={attr.title}
collectionId={collection.id}
attrTitle={attr.title}
>
{attr.title}
</DraggagleTableHeader>)}
</tr>
{items.length && items.map((item) => {
{orderedItems.map((item, index) => {
return (
<tr key={`${item.id}`}>{mapCellsFromValues(item)}</tr>
<tr key={`${index}-${item.id}`}>{mapCellsFromValues(collection.id, `row-${index}`, item)}</tr>
);
})}
</tbody>
Expand Down
28 changes: 20 additions & 8 deletions src/components/landscape-view.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";
import { ICollection, IProcessedCaseObj, ITableProps } from "../types";
import { DraggagleTableHeader } from "./draggable-table-tags";

import css from "./tables.scss";

Expand All @@ -18,9 +19,11 @@ export const LandscapeView = (props: ITableProps) => {
<th colSpan={valueCount}>{parentColl.name}</th>
</tr> }
<tr className={css[className]}>
{firstRowValues.map(values => mapHeadersFromValues(values))}
{firstRowValues.map(values => mapHeadersFromValues(parentColl.id, "first-row", values))}
</tr>
<tr className={css[className]}>
{firstRowValues.map(values => mapCellsFromValues(parentColl.id, "first-row", values))}
</tr>
<tr className={css[className]}>{firstRowValues.map(values => mapCellsFromValues(values))}</tr>
<tr className={css[className]}>
{parentColl.cases.map((caseObj) => {
return (
Expand All @@ -30,7 +33,7 @@ export const LandscapeView = (props: ITableProps) => {
style={{...paddingStyle, verticalAlign: "top"}}
colSpan={Object.values(caseObj.values).length}>
<div style={{width: `100%`, overflow: "scroll"}}>
{renderColFromCaseObj(caseObj)}
{renderColFromCaseObj(parentColl, caseObj)}
</div>
</td>
);
Expand All @@ -40,7 +43,7 @@ export const LandscapeView = (props: ITableProps) => {
);
};

const renderColFromCaseObj = (caseObj: IProcessedCaseObj, index?: number) => {
const renderColFromCaseObj = (collection: ICollection, caseObj: IProcessedCaseObj, index?: number) => {
const {children, values} = caseObj;
const isFirstIndex = index === 0;
if (!children.length) {
Expand All @@ -52,8 +55,12 @@ export const LandscapeView = (props: ITableProps) => {
<th colSpan={Object.keys(values).length}>{caseObj.collection.name}</th>
</tr>
}
{isFirstIndex && <tr className={css[className]}>{mapHeadersFromValues(values)}</tr>}
<tr>{mapCellsFromValues(values)}</tr>
{isFirstIndex &&
<tr className={css[className]}>
{mapHeadersFromValues(collection.id, `first-row-${index}`, values)}
</tr>
}
<tr>{mapCellsFromValues(collection.id, `row-${index}`, values)}</tr>
</>
);
} else {
Expand All @@ -68,7 +75,7 @@ export const LandscapeView = (props: ITableProps) => {
{anyChildHasChildren ?
renderNestedTable(filteredCollection) :
caseObj.children.map((child: IProcessedCaseObj, i: number) => {
return renderColFromCaseObj(child, i);
return renderColFromCaseObj(collection, child, i);
})
}
</tbody>
Expand All @@ -86,7 +93,12 @@ export const LandscapeView = (props: ITableProps) => {
<table className={`${css.mainTable} ${css.landscapeTable} ${css.landscape} ${css[className]}`}>
<tbody>
<tr className={css.mainHeader}>
<th colSpan={getValueLength(firstRowValues)}>{selectedDataSet.name}</th>
<DraggagleTableHeader
collectionId={parentColl[0].id}
attrTitle={selectedDataSet.name}
colSpan={getValueLength(firstRowValues)}>
{selectedDataSet.name}
</DraggagleTableHeader>
</tr>
{renderNestedTable(parentColl[0])}
</tbody>
Expand Down
57 changes: 40 additions & 17 deletions src/components/nested-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { PortraitView } from "./portrait-view";
import { Menu } from "./menu";
import { LandscapeView } from "./landscape-view";
import { FlatTable } from "./flat-table";
import { DraggableTableContext, useDraggableTable } from "../hooks/useDraggableTable";
import { DraggagleTableData, DraggagleTableHeader } from "./draggable-table-tags";

import css from "./nested-table.scss";

Expand All @@ -21,14 +23,23 @@ interface IProps {
handleSelectDataSet: (e: React.ChangeEvent<HTMLSelectElement>) => void
updateInteractiveState: (update: Partial<InteractiveState>) => void
handleShowComponent: () => void
handleSetCollections: (collections: Array<ICollection>) => void
handleUpdateAttributePosition: (collection: ICollection, attrName: string, newPosition: number) => void,
}

export const NestedTable = (props: IProps) => {
const {selectedDataSet, dataSets, collections, items, interactiveState,
handleSelectDataSet, updateInteractiveState, handleShowComponent} = props;
handleSelectDataSet, updateInteractiveState, handleShowComponent,
handleSetCollections, handleUpdateAttributePosition} = props;
const [collectionClasses, setCollectionClasses] = useState<Array<ICollectionClass>>([]);
const [paddingStyle, setPaddingStyle] = useState<Record<string, string>>({padding: "0px"});

const draggableTable = useDraggableTable({
collections,
handleSetCollections,
handleUpdateAttributePosition
});

useEffect(() => {
if (collections.length) {
const classes = collections.map((coll: ICollection, idx: number) => {
Expand Down Expand Up @@ -75,30 +86,40 @@ export const NestedTable = (props: IProps) => {
updateInteractiveState({displayMode: e.target.value});
}, [updateInteractiveState]);

const mapHeadersFromValues = (values: IValues) => {
const mapHeadersFromValues = (collectionId: number, rowKey: string, values: IValues) => {
return (
<>
{(Object.keys(values)).map((key, index) => {
if (typeof values[key] === "string" || typeof values[key] === "number") {
return (<th key={`${key}-${index}`}>{key}</th>);
}
return (
<DraggagleTableHeader
key={`${collectionId}-${rowKey}-${key}-${index}`}
collectionId={collectionId}
attrTitle={key}
>{key}
</DraggagleTableHeader>
);
}
)}
})}
</>
);
};

const mapCellsFromValues = (values: IValues) => {
return (
<>
{(Object.values(values)).map((val, index) => {
if (typeof val === "string" || typeof val === "number") {
return (<td key={`${val}-${index}}`}>{val}</td>);
}
}
)}
</>
);
const mapCellsFromValues = (collectionId: number, rowKey: string, values: IValues) => {
return Object.keys(values).map((key, index) => {
const val = values[key];
if (typeof val === "string" || typeof val === "number") {
return (
<DraggagleTableData
collectionId={collectionId}
attrTitle={key}
key={`${rowKey}-${val}-${index}}`}
>
{val}
</DraggagleTableData>
);
}
});
};

const getValueLength = (firstRow: Array<IValues>) => {
Expand Down Expand Up @@ -143,7 +164,9 @@ export const NestedTable = (props: IProps) => {
padding={interactiveState.padding}
displayMode={interactiveState.displayMode}
/>
{selectedDataSet && renderTable()}
<DraggableTableContext.Provider value={draggableTable}>
{selectedDataSet && renderTable()}
</DraggableTableContext.Provider>
</div>
);
};
Expand Down
Loading

0 comments on commit c3dbebb

Please sign in to comment.