83 |
84 | {isEditing ? (
85 | }
88 | onClick={saveEditedTodo}
89 | style={{ backgroundColor: "green", borderColor: "green" }}
90 | />
91 | ) : (
92 | }
95 | onClick={() => setIsEditing(true)}
96 | />
97 | )}
98 | }
102 | onClick={deleteTodo}
103 | />
104 |
105 |
106 |
107 |
108 | );
109 | };
110 |
111 | export default TodoItem;
112 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/webstorm+all,visualstudiocode,nextjs
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=webstorm+all,visualstudiocode,nextjs
3 |
4 | ### NextJS ###
5 | # dependencies
6 | /node_modules
7 | /.pnp
8 | .pnp.js
9 |
10 | # testing
11 | /coverage
12 |
13 | # next.js
14 | /.next/
15 | /out/
16 |
17 | # production
18 | /build
19 |
20 | # misc
21 | .DS_Store
22 | *.pem
23 |
24 | # debug
25 | npm-debug.log*
26 | yarn-debug.log*
27 | yarn-error.log*
28 | .pnpm-debug.log*
29 |
30 | # local env files
31 | .env*.local
32 |
33 | # vercel
34 | .vercel
35 |
36 | # typescript
37 | *.tsbuildinfo
38 | next-env.d.ts
39 |
40 | ### VisualStudioCode ###
41 | .vscode/*
42 | !.vscode/settings.json
43 | !.vscode/tasks.json
44 | !.vscode/launch.json
45 | !.vscode/extensions.json
46 | !.vscode/*.code-snippets
47 |
48 | # Local History for Visual Studio Code
49 | .history/
50 |
51 | # Built Visual Studio Code Extensions
52 | *.vsix
53 |
54 | ### VisualStudioCode Patch ###
55 | # Ignore all local history of files
56 | .history
57 | .ionide
58 |
59 | ### WebStorm+all ###
60 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
61 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
62 |
63 | # User-specific stuff
64 | .idea/**/workspace.xml
65 | .idea/**/tasks.xml
66 | .idea/**/usage.statistics.xml
67 | .idea/**/dictionaries
68 | .idea/**/shelf
69 |
70 | # AWS User-specific
71 | .idea/**/aws.xml
72 |
73 | # Generated files
74 | .idea/**/contentModel.xml
75 |
76 | # Sensitive or high-churn files
77 | .idea/**/dataSources/
78 | .idea/**/dataSources.ids
79 | .idea/**/dataSources.local.xml
80 | .idea/**/sqlDataSources.xml
81 | .idea/**/dynamic.xml
82 | .idea/**/uiDesigner.xml
83 | .idea/**/dbnavigator.xml
84 |
85 | # Gradle
86 | .idea/**/gradle.xml
87 | .idea/**/libraries
88 |
89 | # Gradle and Maven with auto-import
90 | # When using Gradle or Maven with auto-import, you should exclude module files,
91 | # since they will be recreated, and may cause churn. Uncomment if using
92 | # auto-import.
93 | # .idea/artifacts
94 | # .idea/compiler.xml
95 | # .idea/jarRepositories.xml
96 | # .idea/modules.xml
97 | # .idea/*.iml
98 | # .idea/modules
99 | # *.iml
100 | # *.ipr
101 |
102 | # CMake
103 | cmake-build-*/
104 |
105 | # Mongo Explorer plugin
106 | .idea/**/mongoSettings.xml
107 |
108 | # File-based project format
109 | *.iws
110 |
111 | # IntelliJ
112 | out/
113 |
114 | # mpeltonen/sbt-idea plugin
115 | .idea_modules/
116 |
117 | # JIRA plugin
118 | atlassian-ide-plugin.xml
119 |
120 | # Cursive Clojure plugin
121 | .idea/replstate.xml
122 |
123 | # SonarLint plugin
124 | .idea/sonarlint/
125 |
126 | # Crashlytics plugin (for Android Studio and IntelliJ)
127 | com_crashlytics_export_strings.xml
128 | crashlytics.properties
129 | crashlytics-build.properties
130 | fabric.properties
131 |
132 | # Editor-based Rest Client
133 | .idea/httpRequests
134 |
135 | # Android studio 3.1+ serialized cache file
136 | .idea/caches/build_file_checksums.ser
137 |
138 | ### WebStorm+all Patch ###
139 | # Ignore everything but code style settings and run configurations
140 | # that are supposed to be shared within teams.
141 |
142 | .idea/*
143 |
144 | !.idea/codeStyles
145 | !.idea/runConfigurations
146 |
147 | # End of https://www.toptal.com/developers/gitignore/api/webstorm+all,visualstudiocode,nextjs
148 |
149 | .idea/
150 | .vscode/
--------------------------------------------------------------------------------
/src/context/TodoContext.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, {
4 | ReactNode,
5 | createContext,
6 | useContext,
7 | useEffect,
8 | useReducer,
9 | } from "react";
10 |
11 | interface Todo {
12 | id: string;
13 | text: string;
14 | completed: boolean;
15 | priority: "low" | "medium" | "high";
16 | }
17 |
18 | type Action =
19 | | {
20 | type: "ADD_TODO";
21 | payload: { text: string; priority: "low" | "medium" | "high" };
22 | }
23 | | { type: "DELETE_TODO"; payload: { id: string } }
24 | | { type: "TOGGLE_TODO"; payload: { id: string } }
25 | | { type: "EDIT_TODO"; payload: { id: string; text: string } }
26 | | {
27 | type: "EDIT_PRIORITY";
28 | payload: { id: string; priority: "low" | "medium" | "high" };
29 | }
30 | | { type: "REORDER_TODOS"; payload: { todos: Todo[] } }
31 | | { type: "SET_TODOS"; payload: Todo[] };
32 |
33 | interface State {
34 | todos: Todo[];
35 | }
36 |
37 | interface TodoContextType {
38 | state: State;
39 | dispatch: React.Dispatch;
40 | }
41 |
42 | const initialState: State = {
43 | todos: [],
44 | };
45 |
46 | const todoReducer = (state: State, action: Action): State => {
47 | switch (action.type) {
48 | case "ADD_TODO":
49 | return {
50 | ...state,
51 | todos: [
52 | ...state.todos,
53 | {
54 | id: Date.now().toString(),
55 | text: action.payload.text,
56 | completed: false,
57 | priority: action.payload.priority,
58 | },
59 | ],
60 | };
61 | case "DELETE_TODO":
62 | return {
63 | ...state,
64 | todos: state.todos.filter((todo) => todo.id !== action.payload.id),
65 | };
66 | case "TOGGLE_TODO":
67 | return {
68 | ...state,
69 | todos: state.todos.map((todo) =>
70 | todo.id === action.payload.id
71 | ? { ...todo, completed: !todo.completed }
72 | : todo,
73 | ),
74 | };
75 | case "EDIT_TODO":
76 | return {
77 | ...state,
78 | todos: state.todos.map((todo) =>
79 | todo.id === action.payload.id
80 | ? { ...todo, text: action.payload.text }
81 | : todo,
82 | ),
83 | };
84 | case "EDIT_PRIORITY":
85 | return {
86 | ...state,
87 | todos: state.todos.map((todo) =>
88 | todo.id === action.payload.id
89 | ? { ...todo, priority: action.payload.priority }
90 | : todo,
91 | ),
92 | };
93 | case "REORDER_TODOS":
94 | return {
95 | ...state,
96 | todos: action.payload.todos,
97 | };
98 | case "SET_TODOS":
99 | return {
100 | ...state,
101 | todos: action.payload,
102 | };
103 | default:
104 | return state;
105 | }
106 | };
107 |
108 | const TodoContext = createContext(undefined);
109 |
110 | export const TodoProvider = ({ children }: { children: ReactNode }) => {
111 | const [state, dispatch] = useReducer(todoReducer, initialState);
112 |
113 | useEffect(() => {
114 | const savedTodos = localStorage.getItem("todos");
115 | if (savedTodos) {
116 | dispatch({ type: "SET_TODOS", payload: JSON.parse(savedTodos) });
117 | }
118 | }, []);
119 |
120 | useEffect(() => {
121 | if (state.todos.length > 0) {
122 | localStorage.setItem("todos", JSON.stringify(state.todos));
123 | }
124 | }, [state.todos]);
125 |
126 | return (
127 |
128 | {children}
129 |
130 | );
131 | };
132 |
133 | export const useTodos = (): TodoContextType => {
134 | const context = useContext(TodoContext);
135 | if (!context) {
136 | throw new Error("useTodos must be used within a TodoProvider");
137 | }
138 | return context;
139 | };
140 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | - Demonstrating empathy and kindness toward other people
21 | - Being respectful of differing opinions, viewpoints, and experiences
22 | - Giving and gracefully accepting constructive feedback
23 | - Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | - Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | - The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | - Trolling, insulting or derogatory comments, and personal or political attacks
33 | - Public or private harassment
34 | - Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | - Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | .
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | - Demonstrating empathy and kindness toward other people
21 | - Being respectful of differing opinions, viewpoints, and experiences
22 | - Giving and gracefully accepting constructive feedback
23 | - Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | - Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | - The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | - Trolling, insulting or derogatory comments, and personal or political attacks
33 | - Public or private harassment
34 | - Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | - Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | designweb.azadeh@gmail.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/src/components/TodoList.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, { useState } from "react";
4 |
5 | import { DeleteOutlined, EditOutlined, SaveOutlined } from "@ant-design/icons";
6 | import { Button, Checkbox, Input, List, Space, Tag } from "antd";
7 |
8 | import { useTodos } from "@/context/TodoContext";
9 |
10 | interface TodoListProps {
11 | filter: "all" | "completed" | "pending";
12 | }
13 |
14 | const TodoList: React.FC = ({ filter }) => {
15 | const { state, dispatch } = useTodos();
16 | const [draggingIndex, setDraggingIndex] = useState(null);
17 | const [editingId, setEditingId] = useState(null);
18 | const [editText, setEditText] = useState("");
19 |
20 | const handleDragStart = (index: number) => {
21 | setDraggingIndex(index);
22 | };
23 |
24 | const handleDragOver = (event: React.DragEvent) => {
25 | event.preventDefault();
26 | };
27 |
28 | const handleDrop = (index: number) => {
29 | if (draggingIndex === null) return;
30 |
31 | const reorderedTodos = [...state.todos];
32 | const [draggedItem] = reorderedTodos.splice(draggingIndex, 1);
33 | reorderedTodos.splice(index, 0, draggedItem);
34 |
35 | dispatch({ type: "REORDER_TODOS", payload: { todos: reorderedTodos } });
36 | setDraggingIndex(null);
37 | };
38 |
39 | const toggleTodo = (id: string) => {
40 | dispatch({ type: "TOGGLE_TODO", payload: { id } });
41 | };
42 |
43 | const deleteTodo = (id: string) => {
44 | dispatch({ type: "DELETE_TODO", payload: { id } });
45 | };
46 |
47 | const startEditing = (id: string, text: string) => {
48 | setEditingId(id);
49 | setEditText(text);
50 | };
51 |
52 | const saveEdit = () => {
53 | if (!editText.trim()) {
54 | alert("متن نمیتواند خالی باشد.");
55 | return;
56 | }
57 | dispatch({
58 | type: "EDIT_TODO",
59 | payload: { id: editingId!, text: editText },
60 | });
61 | setEditingId(null);
62 | setEditText("");
63 | };
64 |
65 | const filteredTodos = state.todos.filter((todo) => {
66 | if (filter === "completed") return todo.completed;
67 | if (filter === "pending") return !todo.completed;
68 | return true;
69 | });
70 |
71 | const getPriorityTagColor = (priority: "low" | "medium" | "high") => {
72 | switch (priority) {
73 | case "low":
74 | return "green";
75 | case "medium":
76 | return "orange";
77 | case "high":
78 | return "red";
79 | default:
80 | return "blue";
81 | }
82 | };
83 |
84 | return (
85 |