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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
/example
/next-example
.idea

coverage
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@absmartly/react-sdk",
"version": "1.2.5",
"version": "1.2.6",
"homepage": "https://github.com/absmartly/react-sdk#README.md",
"bugs": "https://github.com/absmartly/react-sdk/issues",
"keywords": [
Expand All @@ -26,20 +26,20 @@
"build:esm": "tsc",
"build:cjs": "tsc --module commonjs --outDir lib/cjs",
"dev": "tsc -w",
"test": "jest"
"test": "jest --coverage"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@types/core-js": "^2.5.5",
"@types/jest": "^29.2.3",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"react": "18.2",
"react-dom": "18.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ts-jest": "^29.0.1",
"ts-node": "^10.9.1",
"typescript": "^4.8.3"
Expand Down
126 changes: 55 additions & 71 deletions src/components/Treatment/Treatment.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
import React, {
cloneElement,
FC,
ReactElement,
ReactNode,
useEffect,
useState,
} from "react";
import React, { FC, ReactNode, useEffect, useState } from "react";

import absmartly from "@absmartly/javascript-sdk";
import { Char } from "../../types";
import { convertLetterToNumber } from "../../utils/convertLetterToNumber";

interface TreatmentProps {
name: string;
context: typeof absmartly.Context;
attributes?: Record<string, unknown>;
loadingComponent?: ReactNode;
children?: ReactNode;
}

interface TreatmentFunctionProps {
name: string;
context: typeof absmartly.Context;
Expand All @@ -27,14 +12,7 @@ interface TreatmentFunctionProps {
children(variantAndVariables: {
variant: number;
variables: Record<string, any>;
}): ReactNode | ReactNode;
}

interface TreatmentVariantProps {
variant: number | Char | undefined;
name?: string;
context?: typeof absmartly.Context;
children?: ReactNode;
}): ReactNode;
}

export const TreatmentFunction: FC<TreatmentFunctionProps> = ({
Expand All @@ -53,9 +31,7 @@ export const TreatmentFunction: FC<TreatmentFunctionProps> = ({
variant: !loadingComponent ? 0 : undefined,
variables: {},
});
const [loading, setLoading] = useState<boolean>(
context && !context.isReady()
);
const [loading, setLoading] = useState<boolean>(!context.isReady());

// Set variant number and variables in state
useEffect(() => {
Expand All @@ -64,9 +40,9 @@ export const TreatmentFunction: FC<TreatmentFunctionProps> = ({
context
.ready()
.then(() => {
//Turning the variable keys and values into an array of arrays
// Turning the variable keys and values into an array of arrays
const variablesArray = Object.keys(context.variableKeys()).map(
(key) => [key, context.peekVariableValue(key)]
(key) => [key, context.peekVariableValue(key, "")]
);

// Converting the array of arrays into a regular object
Expand All @@ -85,26 +61,34 @@ export const TreatmentFunction: FC<TreatmentFunctionProps> = ({
setLoading(false);
})
.catch((e: Error) => console.error(e));
}, [context]);
}, [context, attributes]);

if (loading) {
return loadingComponent != null ? (
<>{loadingComponent}</>
) : (
<>{children({ ...variantAndVariables, variant: 0 })}</>
);
}

return (
<TreatmentVariant
context={context}
name={name}
variant={variantAndVariables.variant}
>
{loading
? loadingComponent
? loadingComponent
: children({ variant: 0, variables: variantAndVariables.variables })
: children({
variant: variantAndVariables.variant || 0,
variables: variantAndVariables.variables,
})}
</TreatmentVariant>
<>
{children({
...variantAndVariables,
variant: variantAndVariables.variant ?? 0,
})}
</>
);
};

interface TreatmentProps {
name: string;
context: typeof absmartly.Context;
attributes?: Record<string, unknown>;
loadingComponent?: ReactNode;
children?: ReactNode;
}

export const Treatment: FC<TreatmentProps> = ({
children,
loadingComponent,
Expand All @@ -116,27 +100,33 @@ export const Treatment: FC<TreatmentProps> = ({
context && !context.isReady()
);

// Turning the children array into objects and mapping them as variants
// and indexes
const childrenInfo = React.Children.map(children, (child, i) => {
// Turning the children into an array of objects and mapping them as variants
const childrenInfo = React.Children.map(children, (child) => {
const obj = child?.valueOf() as {
props: { variant: number | Char };
};
return { variant: obj.props.variant, index: i };
return { variant: obj.props.variant };
});

// Get the index of the first child with a variant matching the context treatment
const getSelectedChildIndex = (context: typeof absmartly.Context) => {
const treatment = context.treatment(name);
return childrenInfo?.filter(
(item) => convertLetterToNumber(item.variant) === (treatment || 0)
)[0]?.index;

const index = childrenInfo?.findIndex(
(x) => convertLetterToNumber(x.variant) === (treatment || 0)
);

if (index === -1) {
return 0;
}

return index ?? 0;
};

// The index of the selected variant in the children array
const [selectedTreatment, setSelectedTreatment] = useState<
number | undefined
>(() => (context?.isReady() ? getSelectedChildIndex(context) : undefined));
const [selectedTreatment, setSelectedTreatment] = useState(
context?.isReady() ? getSelectedChildIndex(context) : null
);

// Making the children prop into an array for selecting a single element later.
const childrenArray = React.Children.toArray(children);
Expand All @@ -155,28 +145,22 @@ export const Treatment: FC<TreatmentProps> = ({
setLoading(false);
})
.catch((e: Error) => console.error(e));
}, [context]);
}, [context, attributes]);

// Return the selected Treatment (Or treatment 0 or loading component)
// Return the selected Treatment
if (loading) {
if (loadingComponent) return loadingComponent as ReactElement;
return childrenArray[0] as ReactElement;
if (loadingComponent) return <>{loadingComponent}</>;
return <>{childrenArray[0]}</>;
}

return cloneElement(childrenArray[selectedTreatment || 0] as ReactElement, {
context,
name,
});
return <>{childrenArray[selectedTreatment || 0]}</>;
};

interface TreatmentVariantProps {
variant: number | Char | undefined;
children?: ReactNode;
}

export const TreatmentVariant: FC<TreatmentVariantProps> = ({ children }) => {
return (
<>
{React.Children.map(children, (child) => {
if (child)
return cloneElement(child as ReactElement)
return null;
})}
</>
);
return <>{children}</>;
};
Loading