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
7 changes: 4 additions & 3 deletions src/components/Todo/Todo.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ export default {
title: "Components/Todo",
component: Todo,
argTypes: {
defaultItems: [{name: "test it", isComplete: false, uuid: '1'}],
defaultItems: [{ name: "test it", isComplete: false, uuid: "1" }],
},
} as Meta;

const Template: Story<TodoAppProps> = (args) => <Todo {...args} />;

export const Example = Template.bind({});
Example.args = {defaultItems: [{name: "test it", isComplete: false, uuid: '1'}]}

Example.args = {
defaultItems: [{ name: "test it", isComplete: false, uuid: "1" }],
};
84 changes: 70 additions & 14 deletions src/components/Todo/Todo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Item, TodoCompletedList } from "./common";
import { Form } from "./common/Todo/Form";
import { TodoItem } from "./common/types";

import uuid from "react-uuid";

export interface TodoAppProps {
defaultItems?: TodoItem[];
onChange: (items: TodoItem[]) => void;
Expand All @@ -15,29 +17,83 @@ function TodoApp(props: TodoAppProps) {
const { defaultItems = [], onChange } = props;
const [items, setItems] = useState<TodoItem[]>(defaultItems);
const [focus, setFocus] = useState(-1);

const setItemsCallback = (updatedItems: TodoItem[]) => {
setItems(updatedItems);
onChange(updatedItems);
};

const addItem = (item: TodoItem | TodoItem[]) => {
const changeFocus = useCallback((focusIndex: number) => {
setFocus(focusIndex);
}, []);

const addItem = (
item: TodoItem | TodoItem[],
cursorLocation?: number | null | undefined,
itemIndex?: number
) => {
const itemsCopy = [...items];
if (Array.isArray(item)) {
item.forEach((it) => {
itemsCopy.unshift(it);
});
setItemsCallback([...itemsCopy]);
//if we're typing in the "Add Item" input...
if (
typeof cursorLocation != "number" ||
Array.isArray(item) ||
itemIndex === undefined
) {
if (Array.isArray(item)) {
item.forEach((it) => {
itemsCopy.unshift(it);
});
setItemsCallback([...itemsCopy]);
} else {
itemsCopy.unshift(item);
setItemsCallback([...itemsCopy]);
}
return;
}
// else if we are typing in any other input
let charsAfterCursor = "";
for (let i = cursorLocation; i < item.name.length; i++) {
charsAfterCursor += item.name[i];
}
let charsBeforeCursor = "";
for (let i = 0; i < cursorLocation; i++) {
charsBeforeCursor += item.name[i];
}
// do nothing if the field we are trying to Enter is blank
if (!charsBeforeCursor && !charsAfterCursor) return;
// split up names based on where cursor is when user clicks Enter
const beforeItem = {
name: charsBeforeCursor,
uuid: uuid(),
isComplete: false,
};
const afterItem = {
name: charsAfterCursor,
uuid: uuid(),
isComplete: false,
};
// insert both halves of the input into the itemsCopy array
itemsCopy.splice(itemIndex, 1, beforeItem, afterItem);
// set items with updated array
setItemsCallback([...itemsCopy]);
// after enter is hit, re-position the cursor depending on where in the input it is
if (!charsBeforeCursor) {
changeFocus(itemsCopy.indexOf(beforeItem));
} else {
itemsCopy.unshift(item);
setItemsCallback([...itemsCopy]);
setTimeout(() => {
const inputs = document.querySelectorAll("input[type='text']");
const inputsArray = Array.from(inputs);
const nextInputElement = inputsArray[
itemsCopy.indexOf(afterItem) + 1
] as HTMLInputElement;
changeFocus(itemsCopy.indexOf(afterItem));
requestAnimationFrame(() => {
nextInputElement.setSelectionRange(0, 0);
});
}, 0);
}
};

const changeFocus = useCallback((focusIndex: number) => {
setFocus(focusIndex);
},[])

const completedItems = items.filter((item: TodoItem) => item.isComplete);
const todoItems = items.filter((item: TodoItem) => !item.isComplete);

Expand Down Expand Up @@ -77,7 +133,7 @@ function TodoApp(props: TodoAppProps) {
);
})}
</Reorder.Group>
<TodoCompletedList
<TodoCompletedList
items={items}
setItemsCallback={setItemsCallback}
completedItems={completedItems}
Expand Down
42 changes: 18 additions & 24 deletions src/components/Todo/common/Todo/CompletedList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import React, { FC } from "react";
import {
Checkbox,
Container,
makeStyles,
Typography
} from "@material-ui/core";
import { Checkbox, Container, makeStyles, Typography } from "@material-ui/core";
import { Accordion } from "../../Accordion";
import { TodoItem } from "../../types";

Expand All @@ -17,7 +12,7 @@ const useStyles = makeStyles({
textDecorationLine: "line-through",
textDecorationStyle: "solid",
padding: "10px 0px 7px",
}
},
});

export interface TodoCompletedItemProps {
Expand Down Expand Up @@ -53,7 +48,6 @@ export const TodoCompletedItem: FC<TodoCompletedItemProps> = ({
return null;
};


export interface TodoCompletedListProps {
items: TodoItem[];
completedItems: TodoItem[];
Expand All @@ -63,24 +57,24 @@ export interface TodoCompletedListProps {
export const TodoCompletedList: FC<TodoCompletedListProps> = ({
completedItems,
items,
setItemsCallback
setItemsCallback,
}) => {
const completedItemsLength = completedItems.length;

if(completedItemsLength === 0) return null;
if (completedItemsLength === 0) return null;

return (
<Accordion title={`${completedItemsLength} Completed items`}>
{items.map((item, index) => {
return (
<TodoCompletedItem
items={items}
key={item.uuid}
itemIndex={index}
setItemsCallback={setItemsCallback}
/>
);
})}
</Accordion>
)
}
<Accordion title={`${completedItemsLength} Completed items`}>
{items.map((item, index) => {
return (
<TodoCompletedItem
items={items}
key={item.uuid}
itemIndex={index}
setItemsCallback={setItemsCallback}
/>
);
})}
</Accordion>
);
};
14 changes: 11 additions & 3 deletions src/components/Todo/common/Todo/Form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {
import { TodoItem } from "../../types";

export interface AddProps {
addItem: (item: TodoItem | TodoItem[]) => void;
addItem: (
item: TodoItem | TodoItem[],
cursorLocation?: number | null | undefined
) => void;
changeFocus: (focusIndex: number) => void;
}

Expand Down Expand Up @@ -68,8 +71,13 @@ export const Form = (props: AddProps) => {
changeFocus(items.length - 1);
}}
onChange={(e) => {

setItemName(e.target.value);
addItem({
name: e.target.value,
uuid: uuid(),
isComplete: false,
});
changeFocus(0);
setItemName("");
}}
placeholder="Add item."
value={itemName}
Expand Down
Loading