Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
TahirMehmood8082 committed Apr 23, 2024
1 parent 88d0466 commit 0547000
Show file tree
Hide file tree
Showing 11 changed files with 816 additions and 30 deletions.
506 changes: 506 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.3",
"get-google-fonts": "^1.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons-kit": "^2.0.0",
"react-redux": "^9.1.1",
"react-scripts": "5.0.1",
"redux": "^5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
59 changes: 40 additions & 19 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,46 @@
import logo from './logo.svg';
import './App.css';
import {useState} from 'react';
import { Form } from "./components/Form";
import { Todos } from "./components/Todos";
import {useDispatch, useSelector} from 'react-redux';
import {deleteAll} from './redux/todoapp/actions';

function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
// dispatch function to dispatch an action
const dispatch = useDispatch();

// getting todos state for conditional rendering
const todos = useSelector((state)=>state.operationsReducer);

// update form visibility state
const [editFormVisibility, setEditFormVisibility]=useState(false);

// editTodo state
const [editTodo, setEditTodo]=useState('');

// this function will trigger when someone clicks the edit icon
const handleEditClick=(todo)=>{
setEditFormVisibility(true);
setEditTodo(todo);
}

// back button click
const cancelUpdate=()=>{
setEditFormVisibility(false);
}

return (
<div className="wrapper">
<br></br>
<h1 className="text-center">TODO-APP USING REACT-REDUX</h1>
<Form editFormVisibility={editFormVisibility} editTodo={editTodo}
cancelUpdate={cancelUpdate}/>
<Todos handleEditClick={handleEditClick} editFormVisibility={editFormVisibility}/>
{todos.length > 1 && (
<button className='btn btn-danger btn-md delete-all'
onClick={()=>dispatch(deleteAll())}>DELETE ALL</button>
)}
</div>
);
}

export default App;
export default App;
71 changes: 71 additions & 0 deletions src/components/Form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React,{useState, useEffect} from 'react'
import { useDispatch } from 'react-redux';
import { addTodo, handleEditSubmit } from '../redux/todoapp/actions';

export const Form = ({editFormVisibility, editTodo, cancelUpdate}) => {

// dispatch function to dispatch an action
const dispatch = useDispatch();

// todo value state for normal add todo form
const [todoValue, setTodoValue]=useState('');

// state for if someone changes the (to edit) value in update form
const [editValue, setEditValue]=useState('');

// useEffect is to show the (to edit) value in update form
useEffect(()=>{
setEditValue(editTodo.todo);
},[editTodo])

// normal add todo submit
const handleSubmit=(e)=>{
e.preventDefault();
let date = new Date();
let time = date.getTime();
let todoObj={
id: time,
todo: todoValue,
completed: false
}
setTodoValue('');
dispatch(addTodo(todoObj))
}

// update form submit
const editSubmit = (e) =>{
e.preventDefault();
let editedObj={
id: editTodo.id,
todo: editValue,
completed: false
}
dispatch(handleEditSubmit(editedObj))
}

return (
<>
{editFormVisibility===false?(
<form className='form-group custom-form' onSubmit={handleSubmit}>
<label>Add your todo-items</label>
<div className='input-and-btn'>
<input type="text" className='form-control' required
value={todoValue} onChange={(e)=>setTodoValue(e.target.value)}/>
<button type="submit" className='btn btn-secondary btn-md'>ADD</button>
</div>
</form>
):(
<form className='form-group custom-form' onSubmit={editSubmit}>
<label>Update your todo-items</label>
<div className='input-and-btn'>
<input type="text" className='form-control' required
value={editValue||""} onChange={(e)=>setEditValue(e.target.value)}/>
<button type="submit" className='btn btn-secondary btn-md'>UPDATE</button>
</div>
<button type="button" className='btn btn-primary btn-md back-btn'
onClick={cancelUpdate}>BACK</button>
</form>
)}
</>
)
}
35 changes: 35 additions & 0 deletions src/components/Todos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react'
import { useSelector, useDispatch } from 'react-redux';
import { Icon } from 'react-icons-kit';
import {trash} from 'react-icons-kit/feather/trash'
import {edit2} from 'react-icons-kit/feather/edit2'
import { removeTodo, handleCheckbox } from '../redux/todoapp/actions';

export const Todos = ({handleEditClick, editFormVisibility}) => {
// dispatch function to dispatch an action
const dispatch = useDispatch();

// getting todos from the store
const todos = useSelector((state)=>state.operationsReducer);
return todos.map((todo)=>(
<div key={todo.id} className='todo-box'>
<div className='content'>
{editFormVisibility===false&&(
<input type="checkbox" checked={todo.completed}
onChange={()=>dispatch(handleCheckbox(todo.id))}></input>
)}
<p style={todo.completed===true?{textDecoration:'line-through'}:{textDecoration:'none'}}>
{todo.todo}
</p>
</div>
<div className='actions-box'>
{editFormVisibility===false&&(
<>
<span onClick={()=>handleEditClick(todo)}><Icon icon={edit2}/></span>
<span onClick={()=>dispatch(removeTodo(todo.id))}><Icon icon={trash}/></span>
</>
)}
</div>
</div>
))
}
66 changes: 57 additions & 9 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,61 @@
body {
*{
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding: 0;
box-sizing: border-box;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
.wrapper{
max-width: 1440px;
width: 100%;
overflow-x: hidden;
overflow-y: auto;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.custom-form{
width: 400px;
height: auto;
margin: 20px auto;
}

.input-and-btn{
display: flex;
}

.todo-box{
width: 400px;
margin: 0 auto;
display: flex;
flex-direction: row;
justify-content: space-between;
}

.todo-box .content{
display: flex;
}

.todo-box .content p{
margin-top: -6px;
margin-left: 6px;
}

.todo-box span{
margin: 0 5px;
}

.delete-all{
width: 400px;
}

.actions-box{
cursor: pointer;
}

.back-btn{
margin-top: 5px;
width: 100%;
}
9 changes: 7 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import '../node_modules/bootstrap/dist/css/bootstrap.css'
import {store} from './redux/store';
import {Provider} from 'react-redux';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
reportWebVitals();
7 changes: 7 additions & 0 deletions src/redux/rootReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { combineReducers } from "redux";
import { operationsReducer } from "./todoapp/reducers/operations";

export const rootReducer = combineReducers({
operationsReducer,
// more reducers can be added here
})
7 changes: 7 additions & 0 deletions src/redux/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { legacy_createStore as createStore } from 'redux';
import {rootReducer} from './rootReducer';

export const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
39 changes: 39 additions & 0 deletions src/redux/todoapp/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export const ADD_TODO = 'ADD_TODO';
export const DELETE_ALL = 'DELETE_ALL';
export const REMOVE_TODO = 'REMOVE_TODO';
export const UPDATE_TODO = 'UPDATE_TODO';
export const UPDATE_CHECKBOX = 'UPDATE_CHECKBOX';

export const addTodo=(payload)=>{
return{
type: ADD_TODO,
payload
}
}

export const deleteAll = () =>{
return{
type: DELETE_ALL
}
}

export const removeTodo=(payload)=>{
return{
type: REMOVE_TODO,
payload
}
}

export const handleEditSubmit=(payload)=>{
return{
type: UPDATE_TODO,
payload
}
}

export const handleCheckbox=(payload)=>{
return{
type: UPDATE_CHECKBOX,
payload
}
}
42 changes: 42 additions & 0 deletions src/redux/todoapp/reducers/operations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-disable array-callback-return */
import { ADD_TODO, DELETE_ALL, REMOVE_TODO, UPDATE_CHECKBOX, UPDATE_TODO } from "../actions";

const initialState=[
{id: 1, todo: 'Buy Laptop', completed: false},
{id: 2, todo: 'Master Redux', completed: false},
{id: 3, todo: 'Watering Plants', completed: true},
];

export const operationsReducer=(state=initialState, action)=>{
switch(action.type){
case ADD_TODO:
return [...state, action.payload];
case DELETE_ALL:
return [];
case REMOVE_TODO:
const filteredTodos = state.filter((todo)=>todo.id!==action.payload);
return filteredTodos;
case UPDATE_TODO:
let data = action.payload;
const updatedArray=[];
state.map((item)=>{
if(item.id===data.id){
item.id = data.id;
item.todo = data.todo;
item.completed = data.completed;
}
updatedArray.push(item);
})
return updatedArray;
case UPDATE_CHECKBOX:
let todoArray=[];
state.map((item)=>{
if(item.id===action.payload){
item.completed = !item.completed;
}
todoArray.push(item);
})
return todoArray;
default: return state;
}
}

0 comments on commit 0547000

Please sign in to comment.