diff --git a/src/App.css b/src/App.css
deleted file mode 100644
index 0304cec..0000000
--- a/src/App.css
+++ /dev/null
@@ -1,71 +0,0 @@
-html {
- background-color: #dbe2ef;
-}
-
-/* Lists */
-.list-item {
- box-sizing: border-box;
- padding: 10px;
- margin: auto;
- display: flex;
- justify-content: space-between;
- width: 1000px;
- height: 80px;
- border-bottom: 2px solid #3f72af;
-}
-
-.list-item:hover {
- background-color: rgba(37, 127, 234, 0.2);
-}
-
-.list-item-col1 {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-}
-
-.list-item-col1-row1 {
- display: flex;
- align-items: center;
-}
-
-.list-item-col1-row1__title {
- font-weight: 500;
- font-size: 18px;
- line-height: 20px;
- color: #000000;
- margin-right: 16px;
-}
-
-.list-item-col1-row1__category {
- font-weight: 400;
- font-size: 18px;
- color: #3f72af;
-}
-
-.list-item-col1-row1__category::before {
- content: url("./icons/folder.svg");
- margin-right: 4px;
- position: relative;
- top: 3px;
-}
-
-.list-item-col1-row2 {
- color: #808080;
- font-weight: 400;
- font-size: 18px;
- line-height: 20px;
-}
-
-.list-item-col2__btn {
- cursor: pointer;
- box-sizing: border-box;
- width: 25px;
- height: 25px;
- border: none;
- background: transparent;
-}
-
-.list-item-col2__btn:first-child {
- margin-right: 15px;
-}
diff --git a/src/App.test.tsx b/src/App.test.tsx
deleted file mode 100644
index 659cc13..0000000
--- a/src/App.test.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import { render } from '@testing-library/react';
-import { Provider } from 'react-redux';
-import { store } from './app/store';
-import App from './App';
-
-test('renders learn react link', () => {
- const { getByText } = render(
-
-
-
- );
-
- expect(getByText(/learn/i)).toBeInTheDocument();
-});
diff --git a/src/Lists/Categories.tsx b/src/Lists/Categories.tsx
deleted file mode 100644
index 35d1b6d..0000000
--- a/src/Lists/Categories.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-/* VENDOR */
-import { useSelector } from "react-redux";
-
-/* APPLICATION */
-import { ListItem } from "./ListItem";
-import { selectAllCategories } from "../features/categoriesSlice";
-
-export const Categories = () => {
- const categories = useSelector(selectAllCategories);
-
- return (
-
- {categories.map((category) => (
-
- ))}
-
- );
-};
diff --git a/src/Lists/ListItem.tsx b/src/Lists/ListItem.tsx
deleted file mode 100644
index d2cc84e..0000000
--- a/src/Lists/ListItem.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/* VENDOR */
-import { useState } from "react";
-import { useSelector } from "react-redux";
-
-/* APPLICATION */
-import edit from "../icons/edit.svg";
-import remove from "../icons/remove.svg";
-import { selectAllCategories } from "../features/categoriesSlice";
-import { ModalEditItem } from "../Modal/ModalEditItem";
-import { ModalRemoveItem } from "../Modal/ModalRemoveItem";
-
-interface ListItemProps {
- item: {
- id: string;
- name: string;
- description: string;
- category?: string;
- };
-}
-
-export const ListItem: React.FC = ({ item }) => {
- const categories = useSelector(selectAllCategories),
- [editModalActive, setEditModalActive] = useState(false)
- let [removeModalActive, setRemoveModalActive] = useState(false);
-
- return (
- <>
-
-
-
-
{item.name}
- {item.category && (
-
- {
- categories.find((category) => category.id === item.category)
- ?.name
- }
-
- )}
-
-
{item.description}
-
-
-
-
-
-
-
-
- >
- );
-};
diff --git a/src/Modal/Modal.css b/src/Modal/Modal.css
deleted file mode 100644
index 3595bd9..0000000
--- a/src/Modal/Modal.css
+++ /dev/null
@@ -1,213 +0,0 @@
-.modal {
- height: 100vh;
- width: 100vw;
- background-color: rgba(0, 0, 0, 0.4);
- position: fixed;
- top: 0;
- left: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- opacity: 0;
- pointer-events: none;
- z-index: 1;
-}
-
-.modal.active {
- opacity: 1;
- pointer-events: all;
-}
-
-.modal__content {
- box-sizing: border-box;
- width: 800px;
- padding: 24px;
- background: #dbe2ef;
- box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.5);
- border-radius: 4px;
-}
-
-.modal__content.small {
- width: 600px;
-}
-
-.modal__content-header {
- display: flex;
- justify-content: space-between;
-}
-
-.modal__content-title {
- font-style: normal;
- font-weight: 500;
- font-size: 40px;
- line-height: 56px;
- color: #3f72af;
- margin-bottom: 32px;
-}
-
-.modal__content-header__btn {
- cursor: pointer;
- box-sizing: border-box;
- width: 25px;
- height: 25px;
- border: none;
- background: transparent;
-}
-
-.modal__content-text {
- margin-bottom: 24px;
- font-style: normal;
- font-weight: 400;
- font-size: 20px;
- line-height: 24px;
- color: #000000;
-}
-
-.modal__content-footer {
- display: flex;
- justify-content: flex-end;
-}
-
-.modal__content_row {
- display: flex;
- justify-content: space-between;
-}
-
-.modalinput {
- box-sizing: border-box;
- padding: 8px;
- height: 46px;
- width: 100%;
- background: transparent;
- border: 2px solid #3f72af;
- border-radius: 4px;
- font-style: normal;
- font-weight: 400;
- font-size: 20px;
- line-height: 46px;
-}
-
-.modalinput::placeholder {
- color: rgba(0, 0, 0, 0.5);
-}
-
-.modalinput-wrapper {
- box-sizing: border-box;
- width: 364px;
- position: relative;
- margin-bottom: 34px;
-}
-
-.modalinput-wrapper.large {
- width: 100%;
-}
-
-.modalinput:focus {
- outline: none;
-}
-
-[for="modalinput"],
-[for="modaltextarea"],
-.dropdown-label {
- font-style: normal;
- display: inline-block;
- background-color: #dbe2ef;
- font-weight: 400;
- padding: 4px;
- font-size: 18px;
- line-height: 20px;
- color: #3f72af;
- position: absolute;
- left: 12px;
- top: -15px;
-}
-
-.modalinput-icon {
- position: absolute;
- left: 55px;
- top: -11px;
- z-index: 1;
-}
-
-.modaltextarea-wrapper {
- position: relative;
-}
-
-.modaltextarea {
- resize: none;
- box-sizing: border-box;
- width: 100%;
- height: 72px;
- margin-bottom: 24px;
- background: transparent;
- border: 2px solid #3f72af;
- border-radius: 4px;
- font-style: normal;
- font-weight: 400;
- font-size: 20px;
- line-height: 26px;
- padding: 8px;
-}
-
-.modaltextarea::placeholder {
- color: rgba(0, 0, 0, 0.5);
-}
-
-.modaltextarea:focus {
- outline: none;
-}
-
-.dropdown {
- cursor: pointer;
- box-sizing: border-box;
- width: 364px;
- height: 24px;
- position: relative;
- z-index: 1;
-}
-
-.dropdown .dropdown-btn {
- box-sizing: border-box;
- padding: 8px;
- display: flex;
- align-items: center; /* для треугольника */
- justify-content: space-between;
- background: #dbe2ef;
- border: 2px solid #3f72af;
- border-radius: 4px;
- font-style: normal;
- font-weight: 400;
- font-size: 20px;
- height: 46px;
- color: #000;
-}
-
-.dropdown .dropdown-btn.placeholder {
- color: rgba(0, 0, 0, 0.5);
-}
-
-.dropdown .dropdown-content {
- box-sizing: border-box;
- position: absolute;
- top: 45px;
- background: #dbe2ef;
- border: 2px solid #3f72af;
- border-radius: 4px;
- width: 364px;
-}
-
-.dropdown .dropdown-content .dropdown-item {
- position: relative;
- left: -2px;
- box-sizing: border-box;
- padding: 10px;
- width: 364px;
- border: none;
- border-radius: 4px;
- color: #3f72af;
-}
-
-.dropdown .dropdown-content .dropdown-item:hover {
- background-color: #3f72ff;
- color: #fff;
-}
diff --git a/src/Modal/ModalRow.tsx b/src/Modal/ModalRow.tsx
deleted file mode 100644
index 2f82d6c..0000000
--- a/src/Modal/ModalRow.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ModalInput } from "./ModalInput";
-import { ModalDropdown } from "./ModalDropdown";
-
-interface ModalRowProps {
- name: string;
- setName: React.Dispatch>;
- selected: string | undefined;
- setSelected: React.Dispatch>;
-}
-
-export const ModalRow: React.FC = ({
- name,
- setName,
- selected,
- setSelected,
-}) => {
- return (
-
-
-
-
- );
-};
diff --git a/src/app/App.test.tsx b/src/app/App.test.tsx
new file mode 100644
index 0000000..2d46f6f
--- /dev/null
+++ b/src/app/App.test.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+import { screen, render } from "@testing-library/react";
+import { Provider } from "react-redux";
+import { store } from "./store/store";
+import App from "./App";
+import { BrowserRouter } from "react-router-dom";
+
+test("renders learn react link", () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByText(/learn/i)).toBeInTheDocument();
+});
diff --git a/src/App.tsx b/src/app/App.tsx
similarity index 68%
rename from src/App.tsx
rename to src/app/App.tsx
index b5a956b..c85eec1 100644
--- a/src/App.tsx
+++ b/src/app/App.tsx
@@ -2,10 +2,10 @@
import { Route, Routes } from "react-router-dom";
/* APPLICATION */
-import "./App.css";
-import { Header } from "./Header/Header";
-import { Tasks } from "./Lists/Tasks";
-import { Categories } from "./Lists/Categories";
+import "./styles/App.css";
+import { Header } from "../components/";
+import { Tasks } from "../pages/Tasks/Tasks";
+import { Categories } from "../pages/Categories/Categories";
function App() {
return (
diff --git a/src/app/hooks.ts b/src/app/hooks/hooks.ts
similarity index 82%
rename from src/app/hooks.ts
rename to src/app/hooks/hooks.ts
index 520e84e..3b36dca 100644
--- a/src/app/hooks.ts
+++ b/src/app/hooks/hooks.ts
@@ -1,5 +1,5 @@
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
-import type { RootState, AppDispatch } from './store';
+import type { RootState, AppDispatch } from '../store/store';
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch();
diff --git a/src/app/store.ts b/src/app/store/store.ts
similarity index 76%
rename from src/app/store.ts
rename to src/app/store/store.ts
index 1bed9d7..6b40fad 100644
--- a/src/app/store.ts
+++ b/src/app/store/store.ts
@@ -1,6 +1,6 @@
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
-import categoriesReducer from "../features/categoriesSlice";
-import tasksReducer from "../features/tasksSlice";
+import categoriesReducer from "../../pages/Categories/categoriesSlice";
+import tasksReducer from "../../pages/Tasks/tasksSlice";
export const store = configureStore({
reducer: {
diff --git a/src/app/styles/App.css b/src/app/styles/App.css
new file mode 100644
index 0000000..d29d158
--- /dev/null
+++ b/src/app/styles/App.css
@@ -0,0 +1,3 @@
+html {
+ background-color: #dbe2ef;
+}
\ No newline at end of file
diff --git a/src/index.css b/src/app/styles/index.css
similarity index 100%
rename from src/index.css
rename to src/app/styles/index.css
diff --git a/src/icons/close.svg b/src/assets/icons/close.svg
similarity index 100%
rename from src/icons/close.svg
rename to src/assets/icons/close.svg
diff --git a/src/icons/down.svg b/src/assets/icons/down.svg
similarity index 100%
rename from src/icons/down.svg
rename to src/assets/icons/down.svg
diff --git a/src/icons/edit.svg b/src/assets/icons/edit.svg
similarity index 100%
rename from src/icons/edit.svg
rename to src/assets/icons/edit.svg
diff --git a/src/icons/folder.svg b/src/assets/icons/folder.svg
similarity index 100%
rename from src/icons/folder.svg
rename to src/assets/icons/folder.svg
diff --git a/src/icons/important.svg b/src/assets/icons/important.svg
similarity index 100%
rename from src/icons/important.svg
rename to src/assets/icons/important.svg
diff --git a/src/logo.svg b/src/assets/icons/logo.svg
similarity index 100%
rename from src/logo.svg
rename to src/assets/icons/logo.svg
diff --git a/src/icons/remove.svg b/src/assets/icons/remove.svg
similarity index 100%
rename from src/icons/remove.svg
rename to src/assets/icons/remove.svg
diff --git a/src/Header/Header.css b/src/components/Header/Header.css
similarity index 100%
rename from src/Header/Header.css
rename to src/components/Header/Header.css
diff --git a/src/Header/Header.tsx b/src/components/Header/Header.tsx
similarity index 94%
rename from src/Header/Header.tsx
rename to src/components/Header/Header.tsx
index 5c09729..2912402 100644
--- a/src/Header/Header.tsx
+++ b/src/components/Header/Header.tsx
@@ -4,7 +4,7 @@ import { Link, useLocation } from "react-router-dom";
/* APPLICATION */
import "./Header.css";
-import { ModalCreateItem } from "../Modal/ModalCreateItem";
+import { ModalCreateItem } from "../../features/ModalCreateItem/ModalCreateItem";
export const Header = () => {
const { pathname } = useLocation(),
diff --git a/src/components/index.ts b/src/components/index.ts
new file mode 100644
index 0000000..a500e76
--- /dev/null
+++ b/src/components/index.ts
@@ -0,0 +1,3 @@
+import {Header} from "./Header/Header";
+
+export {Header}
\ No newline at end of file
diff --git a/src/Modal/ModalCreateItem.tsx b/src/features/ModalCreateItem/ModalCreateItem.tsx
similarity index 54%
rename from src/Modal/ModalCreateItem.tsx
rename to src/features/ModalCreateItem/ModalCreateItem.tsx
index d58b075..d99f7a8 100644
--- a/src/Modal/ModalCreateItem.tsx
+++ b/src/features/ModalCreateItem/ModalCreateItem.tsx
@@ -1,28 +1,26 @@
/* VENDOR */
-import { useState } from "react";
-import { useDispatch } from "react-redux";
+import React, { useState } from "react";
import { useLocation } from "react-router-dom";
/* APPLICATION */
-import { Modal } from "./Modal";
-import { ModalHeader } from "./ModalHeader";
-import { ModalInput } from "./ModalInput";
-import { ModalRow } from "./ModalRow";
-import { ModalTextarea } from "./ModalTextarea";
-import { ModalFooter } from "./ModalFooter";
-import { tasksAdded } from "../features/tasksSlice";
-import { categoriesAdded } from "../features/categoriesSlice";
-
-interface ModalCreateItemProps {
- active: boolean;
- setActive: React.Dispatch>;
-}
+import {
+ Modal,
+ ModalHeader,
+ ModalInput,
+ ModalRow,
+ ModalTextarea,
+ ModalFooter,
+} from "../../shared/ui/Modal";
+import { tasksAdded } from "../../pages/Tasks/tasksSlice";
+import { categoriesAdded } from "../../pages/Categories/categoriesSlice";
+import { useAppDispatch } from "../../app/hooks/hooks";
+import { ModalCreateItemProps } from "../../shared/types/item";
export const ModalCreateItem: React.FC = ({
active,
setActive,
}) => {
- const dispatch = useDispatch(),
+ const dispatch = useAppDispatch(),
{ pathname } = useLocation(),
isCategories = pathname.includes("categories"),
[name, setName] = useState(""),
@@ -35,6 +33,21 @@ export const ModalCreateItem: React.FC = ({
setSelected("");
}
+ const handleSubmit = () => {
+ if (!name) return;
+ dispatch(
+ isCategories
+ ? categoriesAdded({ name, description })
+ : tasksAdded({
+ name,
+ description,
+ category: selected,
+ }),
+ );
+ clearState();
+ setActive(false);
+ };
+
return (
= ({
clearState={clearState}
submitBtnText="Создать"
size="large"
- onSubmit={
- name
- ? () => {
- dispatch(
- isCategories
- ? categoriesAdded({ name, description })
- : tasksAdded({
- name,
- description,
- category: setSelected,
- })
- );
- clearState();
- setActive(false);
- }
- : () => {}
- }
+ onSubmit={handleSubmit}
/>
);
diff --git a/src/Modal/ModalEditItem.tsx b/src/features/ModalEditItem/ModalEditItem.tsx
similarity index 53%
rename from src/Modal/ModalEditItem.tsx
rename to src/features/ModalEditItem/ModalEditItem.tsx
index f6fde0c..8c3c8e7 100644
--- a/src/Modal/ModalEditItem.tsx
+++ b/src/features/ModalEditItem/ModalEditItem.tsx
@@ -1,41 +1,48 @@
/* VENDOR */
-import { useState } from "react";
-import { useDispatch } from "react-redux";
+import React, { useState } from "react";
import { useLocation } from "react-router-dom";
/* APPLICATION */
-import { Modal } from "./Modal";
-import { ModalHeader } from "./ModalHeader";
-import { ModalRow } from "./ModalRow";
-import { ModalInput } from "./ModalInput";
-import { ModalTextarea } from "./ModalTextarea";
-import { ModalFooter } from "./ModalFooter";
-import { tasksUpdated } from "../features/tasksSlice";
-import { categoriesUpdated } from "../features/categoriesSlice";
-
-interface ModalEditItemProps {
- item: {
- id: string;
- name: string;
- description: string;
- category?: string;
- };
- active: boolean;
- setActive: React.Dispatch>;
-}
+import {
+ Modal,
+ ModalHeader,
+ ModalRow,
+ ModalInput,
+ ModalTextarea,
+ ModalFooter,
+} from "../../shared/ui/Modal";
+import { tasksUpdated } from "../../pages/Tasks/tasksSlice";
+import { categoriesUpdated } from "../../pages/Categories/categoriesSlice";
+import { useAppDispatch } from "../../app/hooks/hooks";
+import { ModalEditItemProps } from "../../shared/types/item";
export const ModalEditItem: React.FC = ({
item,
active,
setActive,
}) => {
- const dispatch = useDispatch(),
+ const dispatch = useAppDispatch(),
{ pathname } = useLocation(),
isCategories = pathname.includes("categories"),
[name, setName] = useState(item.name),
[selected, setSelected] = useState(item.category || ""),
[description, setDescription] = useState(item.description);
+ const handleSubmit = () => {
+ if (isCategories) {
+ dispatch(categoriesUpdated({ id: item.id, name, description }));
+ } else {
+ dispatch(
+ tasksUpdated({
+ id: item.id,
+ name,
+ description,
+ category: selected,
+ }),
+ );
+ }
+ setActive(false);
+ };
return (
= ({
setActive={setActive}
submitBtnText="Сохранить"
size="large"
- onSubmit={() => {
- dispatch(
- isCategories
- ? categoriesUpdated({ id: item.id, name, description })
- : tasksUpdated({
- id: item.id,
- name,
- description,
- category: selected,
- })
- );
- setActive(false);
- }}
+ onSubmit={handleSubmit}
/>
);
diff --git a/src/Modal/ModalRemoveItem.tsx b/src/features/ModalRemoveItem/ModalRemoveItem.tsx
similarity index 60%
rename from src/Modal/ModalRemoveItem.tsx
rename to src/features/ModalRemoveItem/ModalRemoveItem.tsx
index 58b47f6..4a6ab56 100644
--- a/src/Modal/ModalRemoveItem.tsx
+++ b/src/features/ModalRemoveItem/ModalRemoveItem.tsx
@@ -1,32 +1,20 @@
/* VENDOR */
-import { useDispatch } from "react-redux";
import { useLocation } from "react-router-dom";
+import React from "react";
/* APPLICATION */
-import { Modal } from "./Modal";
-import { ModalHeader } from "./ModalHeader";
-import { ModalText } from "./ModalText";
-import { ModalFooter } from "./ModalFooter";
-import { tasksRemoved, tasksClearedCategories } from "../features/tasksSlice";
-import { categoriesRemoved } from "../features/categoriesSlice";
-
-interface ModalRemoveItemProps {
- item: {
- id: string;
- name: string;
- description: string;
- category?: string;
- };
- active: boolean;
- setActive: React.Dispatch>;
-}
+import { Modal, ModalHeader, ModalText, ModalFooter } from "../../shared/ui/Modal";
+import { tasksRemoved, tasksClearedCategories } from "../../pages/Tasks/tasksSlice";
+import { categoriesRemoved } from "../../pages/Categories/categoriesSlice";
+import {useAppDispatch} from "../../app/hooks/hooks";
+import {ModalRemoveItemProps} from "../../shared/types/item";
export const ModalRemoveItem: React.FC = ({
item,
active,
setActive,
}) => {
- const dispatch = useDispatch(),
+ const dispatch = useAppDispatch(),
{ pathname } = useLocation(),
isCategories = pathname.includes("categories"),
text = `Вы уверены, что хотите удалить задачу "${item.name}"?`;
diff --git a/src/index.tsx b/src/index.tsx
index ba2f6f0..032f1ea 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -5,10 +5,10 @@ import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
/* APPLICATION */
-import { store } from "./app/store";
-import App from "./App";
+import { store } from "./app/store/store";
+import App from "./app/App";
//import reportWebVitals from './reportWebVitals';
-import "./index.css";
+import "./app/styles/index.css";
const container = document.getElementById("root")!;
const root = createRoot(container);
diff --git a/src/pages/Categories/Categories.tsx b/src/pages/Categories/Categories.tsx
new file mode 100644
index 0000000..6be67cb
--- /dev/null
+++ b/src/pages/Categories/Categories.tsx
@@ -0,0 +1,18 @@
+/* VENDOR */
+
+/* APPLICATION */
+import { ListItem } from "../../shared/ui/ListItem";
+import { selectAllCategories } from "./categoriesSlice";
+import {useAppSelector} from "../../app/hooks/hooks";
+
+export const Categories = () => {
+ const categories = useAppSelector(selectAllCategories);
+
+ return (
+
+ {categories.map((category) => (
+
+ ))}
+
+ );
+};
diff --git a/src/features/categoriesSlice.ts b/src/pages/Categories/categoriesSlice.ts
similarity index 79%
rename from src/features/categoriesSlice.ts
rename to src/pages/Categories/categoriesSlice.ts
index e4876f7..56afa60 100644
--- a/src/features/categoriesSlice.ts
+++ b/src/pages/Categories/categoriesSlice.ts
@@ -3,13 +3,10 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { v4 as uuidv4 } from "uuid";
/* APPLICATION */
-import { RootState } from "../app/store";
+import { RootState } from "../../app/store/store";
+import {Item} from "../../shared/types/item";
-export interface CategoriesState {
- id: string;
- name: string;
- description: string;
-}
+type CategoriesState = Omit-
const initialState: CategoriesState[] = [
{
@@ -33,13 +30,13 @@ export const categoriesSlice = createSlice({
name: "categories",
initialState,
reducers: {
- categoriesAdded: (state, action) => {
+ categoriesAdded: (state, action: PayloadAction>) => {
state.push({
id: uuidv4(),
...action.payload,
});
},
- categoriesUpdated: (state, action) => {
+ categoriesUpdated: (state, action: PayloadAction) => {
const { id, name, description } = action.payload,
existingCategory = state.find((category) => category.id === id);
@@ -50,9 +47,9 @@ export const categoriesSlice = createSlice({
},
categoriesRemoved: (
state: CategoriesState[],
- action: PayloadAction
+ action: PayloadAction
) => {
- let rm = (el: CategoriesState, i: number, arr: CategoriesState[]) =>
+ let rm = (el: CategoriesState) =>
el.id === action.payload,
rmTaskIndex = state.findIndex(rm);
diff --git a/src/Lists/Tasks.tsx b/src/pages/Tasks/Tasks.tsx
similarity index 60%
rename from src/Lists/Tasks.tsx
rename to src/pages/Tasks/Tasks.tsx
index 27a5ff1..14a0354 100644
--- a/src/Lists/Tasks.tsx
+++ b/src/pages/Tasks/Tasks.tsx
@@ -1,12 +1,12 @@
/* VENDOR */
-import { useSelector } from "react-redux";
/* APPLICATION */
-import { ListItem } from "./ListItem";
-import { selectAllTasks } from "../features/tasksSlice";
+import { ListItem } from "../../shared/ui/ListItem";
+import { selectAllTasks } from "./tasksSlice";
+import {useAppSelector} from "../../app/hooks/hooks";
export const Tasks: React.FC = () => {
- const tasks = useSelector(selectAllTasks);
+ const tasks = useAppSelector(selectAllTasks);
return (
diff --git a/src/features/tasksSlice.ts b/src/pages/Tasks/tasksSlice.ts
similarity index 79%
rename from src/features/tasksSlice.ts
rename to src/pages/Tasks/tasksSlice.ts
index 4ba7f07..f75d30c 100644
--- a/src/features/tasksSlice.ts
+++ b/src/pages/Tasks/tasksSlice.ts
@@ -3,16 +3,12 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { v4 as uuidv4 } from "uuid";
/* APPLICATION */
-import { RootState } from "../app/store";
+import { RootState } from "../../app/store/store";
+import {Item} from "../../shared/types/item";
-export interface CategoriesState {
- id: string;
- name: string;
- description: string;
- category: string;
-}
+type TaskState = Item;
-const initialState: CategoriesState[] = [
+const initialState: TaskState[] = [
{
id: "dcf6c7ea-56fe-4e36-960b-686ebf86d651",
name: "Задача",
@@ -37,13 +33,13 @@ export const tasksSlice = createSlice({
name: "tasks",
initialState,
reducers: {
- tasksAdded: (state, action) => {
+ tasksAdded: (state, action: PayloadAction>) => {
state.push({
id: uuidv4(),
...action.payload,
});
},
- tasksUpdated: (state, action) => {
+ tasksUpdated: (state, action:PayloadAction) => {
const { id, name, description, category } = action.payload,
existingTask = state.find((task) => task.id === id);
@@ -53,15 +49,15 @@ export const tasksSlice = createSlice({
existingTask.category = category;
}
},
- tasksRemoved: (state, action) => {
- let rm = (el: CategoriesState, i: number, arr: CategoriesState[]) =>
+ tasksRemoved: (state, action:PayloadAction) => {
+ let rm = (el: TaskState) =>
el.id === action.payload,
rmTaskIndex = state.findIndex(rm);
state.splice(rmTaskIndex, 1);
},
tasksClearedCategories: (state, action) => {
- state.map((task) => {
+ state.forEach((task) => {
if (task.category === action.payload) task.category = "";
});
},
diff --git a/src/shared/types/item.ts b/src/shared/types/item.ts
new file mode 100644
index 0000000..4d8a3d7
--- /dev/null
+++ b/src/shared/types/item.ts
@@ -0,0 +1,27 @@
+import React from "react";
+
+export type Item = {
+ id: string;
+ name: string;
+ description: string;
+ category?: string;
+}
+export interface ModalActiveProps{
+ active: boolean;
+ setActive: React.Dispatch>;
+}
+export interface ModalCreateItemProps extends ModalActiveProps{}
+export interface ModalEditItemProps extends ModalActiveProps{
+ item: Item;
+}
+export interface ModalRemoveItemProps extends ModalActiveProps{
+ item: Item;
+}
+export interface ModalNameProps {
+ name: string;
+ setName: React.Dispatch>;
+}
+export interface ModalDropdownProps {
+ selected: string | undefined;
+ setSelected: React.Dispatch>;
+}
\ No newline at end of file
diff --git a/src/shared/ui/ListItem/ListItem.css b/src/shared/ui/ListItem/ListItem.css
new file mode 100644
index 0000000..40f6adb
--- /dev/null
+++ b/src/shared/ui/ListItem/ListItem.css
@@ -0,0 +1,72 @@
+.list-item {
+ box-sizing: border-box;
+ padding: 10px;
+ margin: auto;
+ display: flex;
+ justify-content: space-between;
+ width: 1000px;
+ height: 100%;
+ border-bottom: 2px solid #3f72af;
+ word-break: break-all;
+}
+
+.list-item:hover {
+ background-color: rgba(37, 127, 234, 0.2);
+}
+
+.list-item-container {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+
+.titleContainer {
+ display: flex;
+ align-items: center;
+}
+
+.itemTitle {
+ font-weight: 500;
+ font-size: 18px;
+ line-height: 20px;
+ color: #000000;
+ margin-right: 16px;
+}
+
+.itemCategory {
+ font-weight: 400;
+ font-size: 18px;
+ color: #3f72af;
+}
+
+.itemCategory::before {
+ content: url("../../../assets/icons/folder.svg");
+ margin-right: 4px;
+ position: relative;
+ top: 3px;
+}
+
+.itemDescription{
+ color: #808080;
+ font-weight: 400;
+ font-size: 18px;
+ line-height: 20px;
+}
+
+.buttonContainer {
+ display: flex;
+ align-items: center;
+}
+
+.itemBtn {
+ cursor: pointer;
+ box-sizing: border-box;
+ width: 25px;
+ height: 25px;
+ border: none;
+ background: transparent;
+}
+
+.itemBtn:first-child {
+ margin-right: 15px;
+}
\ No newline at end of file
diff --git a/src/shared/ui/ListItem/ListItem.tsx b/src/shared/ui/ListItem/ListItem.tsx
new file mode 100644
index 0000000..d19e420
--- /dev/null
+++ b/src/shared/ui/ListItem/ListItem.tsx
@@ -0,0 +1,71 @@
+/* VENDOR */
+import React, { useState } from "react";
+
+/* APPLICATION */
+import edit from "../../../assets/icons/edit.svg";
+import remove from "../../../assets/icons/remove.svg";
+import { selectAllCategories } from "../../../pages/Categories/categoriesSlice";
+import { ModalEditItem } from "../../../features/ModalEditItem/ModalEditItem";
+import { ModalRemoveItem } from "../../../features/ModalRemoveItem/ModalRemoveItem";
+import './ListItem.css'
+import {useAppSelector} from "../../../app/hooks/hooks";
+import {Item} from "../../types/item";
+
+interface ListItemProps {
+ item: Item;
+}
+
+export const ListItem: React.FC = ({ item }) => {
+ const categories = useAppSelector(selectAllCategories),
+ [editModalActive, setEditModalActive] = useState(false),
+ [removeModalActive, setRemoveModalActive] = useState(false);
+
+ return (
+ <>
+ -
+
+
+
{item.name}
+ {item.category && (
+
+ {
+ categories.find((category) => category.id === item.category)
+ ?.name
+ }
+
+ )}
+
+
{item.description}
+
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/src/shared/ui/ListItem/index.ts b/src/shared/ui/ListItem/index.ts
new file mode 100644
index 0000000..64d728d
--- /dev/null
+++ b/src/shared/ui/ListItem/index.ts
@@ -0,0 +1,3 @@
+import {ListItem} from "./ListItem";
+
+export {ListItem}
\ No newline at end of file
diff --git a/src/shared/ui/Modal/Modal.css b/src/shared/ui/Modal/Modal.css
new file mode 100644
index 0000000..b1d48da
--- /dev/null
+++ b/src/shared/ui/Modal/Modal.css
@@ -0,0 +1,32 @@
+.modal {
+ height: 100vh;
+ width: 100vw;
+ background-color: rgba(0, 0, 0, 0.4);
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ opacity: 0;
+ pointer-events: none;
+ z-index: 1;
+}
+
+.modal.active {
+ opacity: 1;
+ pointer-events: all;
+}
+
+.modal__content {
+ box-sizing: border-box;
+ width: 800px;
+ padding: 24px;
+ background: #dbe2ef;
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+}
+
+.modal__content.small {
+ width: 600px;
+}
\ No newline at end of file
diff --git a/src/Modal/Modal.tsx b/src/shared/ui/Modal/Modal.tsx
similarity index 72%
rename from src/Modal/Modal.tsx
rename to src/shared/ui/Modal/Modal.tsx
index 5075fed..7b8aa98 100644
--- a/src/Modal/Modal.tsx
+++ b/src/shared/ui/Modal/Modal.tsx
@@ -3,16 +3,10 @@ import React from "react";
/* APPLICATION */
import "./Modal.css";
+import {Item, ModalActiveProps} from "../../types/item";
-interface ModalProps {
- item?: {
- id: string;
- name: string;
- description: string;
- category?: string;
- };
- active: boolean;
- setActive: React.Dispatch>;
+interface ModalProps extends ModalActiveProps{
+ item?: Item;
children: React.ReactNode;
clearState?(): void;
}
diff --git a/src/Modal/ModalBtn.css b/src/shared/ui/Modal/ModalBtn.css
similarity index 73%
rename from src/Modal/ModalBtn.css
rename to src/shared/ui/Modal/ModalBtn.css
index a676482..292d060 100644
--- a/src/Modal/ModalBtn.css
+++ b/src/shared/ui/Modal/ModalBtn.css
@@ -4,7 +4,6 @@
width: 120px;
font-weight: 400;
font-size: 20px;
- line-height: 46px;
color: #3f72af;
border: 2px solid #3f72af;
background: transparent;
@@ -12,15 +11,21 @@
cursor: pointer;
}
+.modalbtn:hover {
+ color: #ffffff;
+ background-color: #3f72af;
+ transition: all 300ms;
+}
+
.modalbtn:first-child {
margin-right: 24px;
}
-.modalbtn.primary {
+.primary {
color: #fff;
background-color: #3f72af;
}
-.modalbtn.primary.large {
+.primary.large {
width: 200px;
-}
+}
\ No newline at end of file
diff --git a/src/Modal/ModalBtn.tsx b/src/shared/ui/Modal/ModalBtn.tsx
similarity index 69%
rename from src/Modal/ModalBtn.tsx
rename to src/shared/ui/Modal/ModalBtn.tsx
index f9bbdcf..8379bc5 100644
--- a/src/Modal/ModalBtn.tsx
+++ b/src/shared/ui/Modal/ModalBtn.tsx
@@ -1,3 +1,5 @@
+import React from "react";
+
import "./ModalBtn.css";
interface ModalBtnProps {
@@ -13,12 +15,7 @@ export const ModalBtn: React.FC = ({
size,
onClick,
}) => {
- const btnClass =
- type === "primary"
- ? size === "large"
- ? "modalbtn primary large"
- : "modalbtn primary"
- : "modalbtn";
+ const btnClass = `modalbtn ${type && "primary"} ${size && "large"}`;
return (