Skip to content

Commit

Permalink
Add useSorting Hook #83 from prismaneui/add-use-sorting-hook
Browse files Browse the repository at this point in the history
Add useSorting Hook
  • Loading branch information
spleafy authored Oct 29, 2023
2 parents 2548ff3 + 835ac01 commit cb8e85c
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ export { default as useNetworkStatus } from "./useNetworkStatus";
export { default as useOutsideClick } from "./useOutsideClick";
export { default as usePresence } from "./usePresence";
export { default as usePrevious } from "./usePrevious";
export { default as useSorting } from "./useSorting";
export { default as useSearch } from "./useSearch";
export { default as useToggle } from "./useToggle";
1 change: 1 addition & 0 deletions src/hooks/useSorting/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./useSorting";
41 changes: 41 additions & 0 deletions src/hooks/useSorting/useSorting.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Stack, Center, Flex, Button, Text } from "../../components";
import { fr } from "../../utils";
import useSorting from "./useSorting";

export default {
title: "useSorting",
component: useSorting,
};

export const Default = () => {
const items = [
{ name: "Apple", quantity: 10 },
{ name: "Banana", quantity: 5 },
{ name: "Cherry", quantity: 15 },
{ name: "Date", quantity: 8 },
];

const { sorted, key, direction, setKey, toggleDirection } = useSorting(
items,
"name"
);

return (
<Stack as={Center}>
<Button onClick={() => setKey("name")}>Sort by Name</Button>
<Button onClick={() => setKey("quantity")}>Sort by Quantity</Button>
<Button onClick={toggleDirection}>Toggle Order</Button>
<Stack mt={fr(6)}>
{sorted.map((item, index) => (
<Text key={index}>
{item.name} - {item.quantity}
</Text>
))}
</Stack>
<Text>
Sorting by: <Text as="strong">{key}</Text> (Order:{" "}
<Text as="strong">{direction}</Text>)
</Text>
</Stack>
);
};
84 changes: 84 additions & 0 deletions src/hooks/useSorting/useSorting.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { renderHook, act } from "@testing-library/react-hooks";
import useSorting from "./useSorting";

describe("useSorting Hook", () => {
it("should initially set sorted data with 'asc' direction", () => {
const data = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
];

const { result } = renderHook(() => useSorting(data, "name"));

expect(result.current.sorted).toEqual(data);
expect(result.current.direction).toBe("asc");
});

it("should sort data by the selected key in ascending order", () => {
const data = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
];

const { result } = renderHook(() => useSorting(data, "name"));

act(() => result.current.toggleDirection());

expect(result.current.sorted).toEqual([
{ name: "Bob", age: 25 },
{ name: "Alice", age: 30 },
]);

act(() => {
result.current.setKey("age");
});

expect(result.current.sorted).toEqual([
{ name: "Bob", age: 25 },
{ name: "Alice", age: 30 },
]);
});

it("should sort data by the selected key in descending order", () => {
const data = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
];

const { result } = renderHook(() => useSorting(data, "name"));

act(() => {
result.current.setKey("age");
});

act(() => {
result.current.toggleDirection();
});

expect(result.current.sorted).toEqual([
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
]);
});

it("should reset direction when key changes", () => {
const data = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
];

const { result } = renderHook(() => useSorting(data, "name"));

act(() => {
result.current.toggleDirection();
});

expect(result.current.direction).toBe("desc");

act(() => {
result.current.setKey("age");
});

expect(result.current.direction).toBe("asc");
});
});
60 changes: 60 additions & 0 deletions src/hooks/useSorting/useSorting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useState, useEffect } from "react";

type useSortingOptions = {
resetDirectionOnKeyChange?: boolean;
};

const useSorting = (
data: any[],
initialKey: string | null = null,
initialDirection: "asc" | "desc" = "asc",
options: useSortingOptions = {
resetDirectionOnKeyChange: true,
}
) => {
const [sorted, setSorted] = useState(data);
const [key, setKey] = useState<string | null>(initialKey);
const [direction, setDirection] = useState(initialDirection);

const toggleDirection = () => {
setDirection((prev) => (prev === "asc" ? "desc" : "asc"));
};

useEffect(() => {
if (options.resetDirectionOnKeyChange) {
setDirection("asc");
}
}, [key]);

useEffect(() => {
if (key !== null) {
const sortedData = [...sorted].sort((a, b) => {
const first = a[key];
const second = b[key];

if (first < second) {
return direction === "asc" ? -1 : 1;
}

if (first > second) {
return direction === "asc" ? 1 : -1;
}

return 0;
});

setSorted(sortedData);
}
}, [data, key, direction]);

return {
sorted,
key,
direction,
setKey,
setDirection,
toggleDirection,
};
};

export default useSorting;

0 comments on commit cb8e85c

Please sign in to comment.