Skip to content
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
4 changes: 2 additions & 2 deletions src/components/containers/Cassette.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ const defaultSample: components["schemas"]["SampleOut"] = {
shipmentId: 1,
proteinId: 1,
details: {
concentration: 1
}
concentration: 1,
},
};

describe("Cassette", () => {
Expand Down
25 changes: 22 additions & 3 deletions src/components/containers/Cassette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,17 @@ export const Cassette = ({ samples }: CassetteProps) => {
() =>
samples.reduce((selectable, sample) => {
if (sample.subLocation === null) {
selectable.push({ id: sample.id, name: sample.name || "", data: sample.details });
selectable.push({
id: sample.id,
name: sample.name || "",
data: {
type: sample.type,
displayDetails: [
{ label: "Grid Box Name", value: sample.containerName },
{ label: "Location", value: sample.location },
],
},
});
}
return selectable;
}, [] as TreeData[]),
Expand Down Expand Up @@ -94,8 +104,16 @@ export const Cassette = ({ samples }: CassetteProps) => {
borderColor='diamond.700'
w='100%'
>
<Tag colorScheme='teal'>{12 - i}</Tag>
<Text ml='0.5em' fontWeight='600' color={item === null ? "diamond.800" : "diamond.50"}>
<Tag colorScheme='teal' minW='30px' justifyContent='center' flexShrink='0'>
{12 - i}
</Tag>
<Text
px='10px'
fontWeight='600'
color={item === null ? "diamond.800" : "diamond.50"}
overflowX='hidden'
textOverflow='ellipsis'
>
{item?.name ?? ""}
</Text>
<Spacer />
Expand All @@ -109,6 +127,7 @@ export const Cassette = ({ samples }: CassetteProps) => {
selectedItem={currentItem}
isOpen={isOpen}
onClose={onClose}
displayDetails={true}
selectableChildren={selectableSamples}
/>
</VStack>
Expand Down
11 changes: 8 additions & 3 deletions src/components/containers/ChildSelector.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,21 +153,26 @@ describe("Child Selector", () => {
childrenType='sample'
isOpen={true}
onClose={() => {}}
selectableChildren={[{ id: 1, name: "selectable-child", data: {} }]}
selectableChildren={[{ id: 1, name: "selectable-child", data: { type: "Grid" } }]}
/>,
);

expect(screen.getByText("selectable-child")).toBeInTheDocument();
});

it("should display details if child is sample", () => {
it("should display details if displayDetails is set", () => {
renderWithProviders(
<ChildSelector
displayDetails={true}
childrenType='sample'
isOpen={true}
onClose={() => {}}
selectableChildren={[
{ id: 1, name: "selectable-child", data: { type: "Sample", concentration: 123 } },
{
id: 1,
name: "selectable-child",
data: { type: "Sample", displayDetails: [{ label: "Concentration", value: 123 }] },
},
]}
/>,
);
Expand Down
36 changes: 18 additions & 18 deletions src/components/containers/ChildSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TreeData } from "@/components/visualisation/treeView";
import { selectUnassigned } from "@/features/shipment/shipmentSlice";
import { BaseShipmentItem, getCurrentStepIndex, steps } from "@/mappings/pages";
import { ChildSelectorProps } from "@/types/generic";
import { getCurrentStepIndex, steps } from "@/mappings/pages";
import { ChildSelectorProps, ItemWithDetails } from "@/types/generic";
import {
Box,
Button,
Expand Down Expand Up @@ -32,9 +32,10 @@ import { useSelector } from "react-redux";

interface ChildItemDetailsProps {
childType: string;
childData: TreeData<BaseShipmentItem>;
childData: TreeData<ItemWithDetails>;
childId: number;
hasCheckbox?: boolean;
displayDetails?: boolean;
}

interface ChildItemDetailsFieldProps {
Expand All @@ -58,27 +59,23 @@ const ChildItemDetails = ({
childData,
childId,
hasCheckbox = false,
displayDetails,
}: ChildItemDetailsProps) => (
<VStack w='100%' key={childId} borderBottom='1px solid' borderColor='diamond.200' py='10px'>
<HStack w='100%'>
<Stat>
<StatLabel>{childType}</StatLabel>
<StatNumber>{childData.name}</StatNumber>
{childType === "Grid" && (
{displayDetails && childData.data.displayDetails && (
<Grid w='100%' gap='0' templateColumns='repeat(2, 1fr)' mt='10px'>
<ChildItemDetailsField
label='Concentration'
value={childData.data.concentration}
measurementUnit='mg/ml'
/>
<ChildItemDetailsField label='Buffer' value={childData.data.buffer} />
<ChildItemDetailsField
label='Support Material'
value={childData.data.supportMaterial}
/>
<ChildItemDetailsField label='Foil' value={childData.data.foil} />
<ChildItemDetailsField label='Mesh' value={childData.data.mesh} />
<ChildItemDetailsField label='Hole Diameter' value={childData.data.hole} />
{childData.data.displayDetails.map((item) => (
<ChildItemDetailsField
key={item.label}
label={item.label}
value={item.value}
measurementUnit={item.measurementUnit}
/>
))}
</Grid>
)}
</Stat>
Expand All @@ -92,6 +89,7 @@ const ChildItemDetails = ({
);

export const ChildSelector = ({
displayDetails,
selectedItem,
childrenType,
onSelect,
Expand All @@ -109,7 +107,7 @@ export const ChildSelector = ({
const [selectedItems, setSelectedItems] = useState<number[]>([]);
const [isLoading, setIsLoading] = useState(false);

const unassignedItems: TreeData<BaseShipmentItem>[] | undefined | null = useMemo(() => {
const unassignedItems: TreeData<ItemWithDetails>[] | undefined | null = useMemo(() => {
if (selectableChildren) {
return selectableChildren;
}
Expand Down Expand Up @@ -209,6 +207,7 @@ export const ChildSelector = ({
childData={item}
childId={i}
hasCheckbox={true}
displayDetails={displayDetails}
/>
))}
</CheckboxGroup>
Expand All @@ -220,6 +219,7 @@ export const ChildSelector = ({
childType={childrenTypeData.data.singular}
childData={item}
childId={i}
displayDetails={displayDetails}
/>
))}
</RadioGroup>
Expand Down
28 changes: 25 additions & 3 deletions src/components/containers/GridBox.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ChildSelector } from "@/components/containers/ChildSelector";
import { TreeData } from "@/components/visualisation/treeView";
import { selectActiveItem } from "@/features/shipment/shipmentSlice";
import { selectActiveItem, selectUnassigned } from "@/features/shipment/shipmentSlice";
import { PositionedItem } from "@/mappings/forms/sample";
import { BaseShipmentItem } from "@/mappings/pages";
import { BaseShipmentItem, getCurrentStepIndex } from "@/mappings/pages";
import { calcCircumferencePos } from "@/utils/generic";
import { Box, useDisclosure, Alert, AlertDescription, AlertIcon, VStack } from "@chakra-ui/react";
import { useCallback, useMemo, useState } from "react";
Expand All @@ -11,7 +11,7 @@ import { ContainerProps, useChildLocationManager } from ".";
import { GenericChildSlot } from "@/components/containers/child";
import { CrossShipmentSelector } from "@/components/containers/CrossShipmentSelector";
import Image from "next/image";
import { ContainerItem } from "@/types/generic";
import { ContainerItem, ItemDetails } from "@/types/generic";

const GRID_BOX_TYPES: Record<string, ContainerItem[]> = {
"1": [
Expand Down Expand Up @@ -61,6 +61,7 @@ export const GridBox = ({
containerSubType,
}: Omit<ContainerProps, "containerType">) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const unassigned = useSelector(selectUnassigned);
const currentGridBox = useSelector(selectActiveItem);
const [currentSample, setCurrentSample] = useState<TreeData<PositionedItem> | null>(null);
const [currentPosition, setCurrentPosition] = useState(0);
Expand All @@ -86,6 +87,25 @@ export const GridBox = ({
return { samples: newSamples, sampleOverload };
}, [currentGridBox, containerSubType]);

const selectableSamples = useMemo(
() =>
unassigned[0].children![getCurrentStepIndex("Grid")].children?.map((grid) => ({
...grid,
data: {
...grid.data,
displayDetails: [
{ label: "Concentration", value: grid.data.concentration, measurementUnit: "mg/ml" },
{ label: "Buffer", value: grid.data.buffer },
{ label: "Support Material", value: grid.data.supportMaterial },
{ label: "Foil", value: grid.data.foil },
{ label: "Mesh", value: grid.data.mesh },
{ label: "Hole Diameter", value: grid.data.hole },
] as ItemDetails[],
},
})),
[unassigned],
);

const setLocation = useChildLocationManager({
parentId,
parent: "containers",
Expand Down Expand Up @@ -143,6 +163,8 @@ export const GridBox = ({
))}
{parentType === "shipment" ? (
<ChildSelector
displayDetails={true}
selectableChildren={selectableSamples}
childrenType='sample'
onSelect={handlePopulatePosition}
onRemove={handleRemoveSample}
Expand Down
18 changes: 15 additions & 3 deletions src/types/generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,28 @@ export type ShipmentItemLayoutProps =

export type ChildSelectorProps = MultipleChildSelectorProps | SingleChildSelectorProps;

export interface ItemDetails {
label: string;
value: string | number;
/** Measurement unit to display for label */
measurementUnit?: string;
}
export interface ItemWithDetails extends BaseShipmentItem {
displayDetails?: ItemDetails[];
}

export interface MultipleChildSelectorProps extends BaseChildSelectorProps {
/** Enable multiple children to be selected */
acceptMultiple: true;
/** Callback for item selection event */
onSelect?: (child: TreeData<BaseShipmentItem>[]) => Promise<void>;
onSelect?: (child: TreeData<ItemWithDetails>[]) => Promise<void>;
}

export interface SingleChildSelectorProps extends BaseChildSelectorProps {
/** Enable multiple children to be selected */
acceptMultiple?: false;
/** Callback for item selection event */
onSelect?: (child: TreeData<BaseShipmentItem>) => Promise<void>;
onSelect?: (child: TreeData<ItemWithDetails>) => Promise<void>;
}

export interface BaseChildSelectorProps extends Omit<ModalProps, "children"> {
Expand All @@ -41,7 +51,9 @@ export interface BaseChildSelectorProps extends Omit<ModalProps, "children"> {
/** Disable editing controls */
readOnly?: boolean;
/** Selectable children. If not provided, unassigned items are used */
selectableChildren?: TreeData[];
selectableChildren?: TreeData<ItemWithDetails>[];
/** Whether to display child details (data of passed children) underneath child name*/
displayDetails?: boolean;
}

export interface SessionParams {
Expand Down