Skip to content

Commit 5c9c26e

Browse files
Merge pull request #4 from MohamedRizwan399/develop
Master - Readme content, License and Code optmization is completed
2 parents 3ae3ca1 + 45adf48 commit 5c9c26e

File tree

11 files changed

+180
-70
lines changed

11 files changed

+180
-70
lines changed

LICENSE

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Custom License for **Javascript CRUD with SampleTasks**
2+
3+
This repository and all its contents are the property of **Mohamed Rizwan**. Use of any part of this repository, including code, documentation, or resources, is only permitted with prior written consent from the owner.
4+
5+
Access to this repository is provided for the purpose of collaboration or review, as approved by the owner. Any use, modification, or distribution of the contents should be done with permission.
6+
7+
For any inquiries regarding permissions, please contact Mohamed Rizwan at **mohamedrizwan399@gmail.com**.

README.md

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,64 @@
1-
# Getting Started with Create React App
2-
3-
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4-
5-
## Available Scripts
6-
7-
In the project directory, you can run:
8-
9-
### `npm start`
10-
1+
# Javascript CRUD with SampleTasks
2+
3+
A Javascript application to demonstrate the comprehensive **CRUD** app built using ReactJS and Firebase. It implement user authentication with both Google Sign-In and username/password login methods, along with other key features such as API handling, local storage CRUD operations, and managing application state using Redux.
4+
The app also leverages modern React hooks, lifecycle methods, and routing for smooth navigation between pages.
5+
6+
## Features
7+
- **User authentication with Google Sign-In**: Users can sign in using their Google accounts using Firebase for secure authentication.
8+
- **Username/Password Authentication**: Custom username and password login using Firebse for added flexibility.
9+
- **CRUD Operations**: Ability to perform create, read, update, and delete operations with data stored in local storage.
10+
- **API Handling with Axios**: Handled API requests using Axios for fetching data from remote servers.
11+
- **Data Management with Redux**: Efficiently manage app state using Redux store to handle data across components.
12+
- **React Hooks and Lifecycle Methods**: Utilization of React hooks like useState, useEffect, useRef and lifecycle methods for optimal component behavior.
13+
- **Dynamic Routing**: Implemented navigation between pages with React Router for a dynamic user experience.
14+
- **Loader Implementation**: Display a loader during asynchronous operations to improve user experience.
15+
- **Responsive UI**: Fully responsive UI with styling using CSS and modern design principles.
16+
- **Header and Footer**: The header includes navigation tabs, and the footer provides links to "About Us" and "Contact Us" pages.
17+
18+
19+
## Prerequisites
20+
You need to install required version:
21+
- Node.js 16 LTS [Download Node.js](https://nodejs.org/)
22+
- Npm 8 >= or yarn
23+
24+
## Steps to Installation
25+
**Step 1:** Clone the repo
26+
```bash
27+
- https://github.com/MohamedRizwan399/CRUDJavaScriptSampleProject.git
28+
```
29+
30+
**Step 2:** Install the dependencies using npm
31+
```bash
32+
- npm install
33+
```
34+
35+
**Step 3:** Run the application
36+
```bash
37+
- npm start
38+
```
1139
Runs the app in the development mode.\
1240
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
1341

1442
The page will reload when you make changes.\
1543
You may also see any lint errors in the console.
1644

17-
### `npm test`
18-
45+
**Step 4:** Run the test suites
46+
```bash
47+
- npm test
48+
```
1949
Launches the test runner in the interactive watch mode.\
2050
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
2151

22-
### `npm run build`
23-
52+
**Step 5:** To run build in Production, if needed
53+
```bash
54+
- npm run build
55+
```
2456
Builds the app for production to the `build` folder.\
2557
It correctly bundles React in production mode and optimizes the build for the best performance.
2658

27-
The build is minified and the filenames include the hashes.\
28-
Your app is ready to be deployed!
29-
30-
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31-
32-
### `npm run eject`
33-
34-
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
35-
36-
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37-
38-
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
39-
40-
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
4159

4260
## Learn More
4361

44-
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45-
4662
To learn React, check out the [React documentation](https://reactjs.org/).
4763

4864
### Code Splitting
@@ -57,14 +73,7 @@ This section has moved here: [https://facebook.github.io/create-react-app/docs/a
5773

5874
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
5975

60-
### Advanced Configuration
61-
62-
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
6376

6477
### Deployment
6578

6679
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67-
68-
### `npm run build` fails to minify
69-
70-
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"axios": "^1.7.7",
1111
"cors": "^2.8.5",
1212
"firebase": "^11.0.1",
13+
"jest": "^27.5.1",
1314
"jwt-decode": "^3.1.2",
1415
"nodemon": "^3.1.7",
1516
"react": "^18.2.0",

src/App.test.js

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
import { render, screen } from '@testing-library/react';
2-
import App from './App';
3-
import Demo from './Demo';
2+
import Popup from './popup/Popup';
43

5-
// test('renders learn react link', () => {
6-
// render(<App />);
7-
// const linkElement = screen.getByText(/learn react/i);
8-
// expect(linkElement).toBeInTheDocument();
9-
// });
4+
//clear local storage
5+
beforeEach(() => {
6+
localStorage.clear();
7+
});
108

11-
12-
// test('demo state test', () => {
13-
// render(<Demo />);
14-
// expect().toBeInTheDocument();
15-
// });
9+
describe("popup component", () => {
10+
test("renders popup with image, message, and button", () => {
11+
const mockSetShowPopup = jest.fn(); //mock function
12+
13+
// Render the Popup component
14+
render(<Popup setShowPopup={mockSetShowPopup} />);
15+
16+
const popupImage = screen.getByRole('img');
17+
expect(popupImage).toBeInTheDocument();
18+
expect(popupImage).toHaveAttribute('src','favicon1.ico');
19+
20+
const boldText1 = document.querySelector('b');
21+
expect(boldText1).toBeInTheDocument();
22+
expect(boldText1.textContent).toBe('myself');
23+
24+
//check ok button
25+
const button = screen.getByRole('button',{name:/OK/i});
26+
expect(button).toBeInTheDocument();
27+
});
28+
})

src/homePage/Card.jsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ const Card = ({post, itemArrLength, isAllCardLoaded}) => {
1010

1111
useEffect(() => {
1212
counter = counter + 1;
13-
if (itemArrLength === counter) {
14-
return () => {
15-
setTimeout(() => { isAllCardLoaded(true) }, 1000);
16-
};
17-
}
13+
const timer = setTimeout(() => {
14+
if (itemArrLength === counter) {
15+
isAllCardLoaded(true)
16+
}
17+
}, 1000);
18+
return () => {
19+
clearTimeout(timer);
20+
counter = 0;
21+
};
1822
}, [itemArrLength, isAllCardLoaded]);
1923

2024
return (

src/homePage/Footer.jsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import React from "react";
2-
import { BrowserRouter, Routes, Route} from 'react-router-dom';
32
import {
43
Box,
54
Container,
65
Row,
76
Column,
87
FooterLink,
9-
Heading,
108
} from "./Footerstyle";
11-
import { Outlet, Link} from "react-router-dom";
129

1310
function Footer() {
1411
return (

src/homePage/HeaderNavbarLogin.jsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'
22
import { Link, NavLink, useNavigate } from 'react-router-dom'
33
import "../App.css"
44
import { auth } from '../loginAuthentication/firebase/FirebaseConfig';
5-
import { signOut, deleteUser } from "firebase/auth";
5+
import { deleteUser } from "firebase/auth";
66
import ClipLoader from 'react-spinners/ClipLoader';
77

88
// SampleProfileUrl - https://images.pexels.com/photos/1742370/pexels-photo-1742370.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500
@@ -19,18 +19,22 @@ const HeaderNavbarLogin = (props) => {
1919
if(loggedInData?.loggedInType === "usernamePwd") {
2020
await auth.signOut();
2121
} else {
22-
signOut(auth).then(() => {
22+
try {
23+
await auth.signOut();
2324
if (user) {
24-
deleteUser(user);
25+
await deleteUser(user);
2526
console.log("User successfully deleted from Firebase.");
2627
}
28+
29+
} catch(exception) {
30+
console.error("Sign out error-->",exception)
2731
setIsLoading(false);
28-
}).catch((e) => {
29-
console.error("Sign out error-->",e)
30-
})
32+
return;
33+
}
3134
}
3235

3336
localStorage.removeItem("loggedInData");
37+
setIsLoading(false);
3438
setLoggedInUser(false);
3539
navigateToNextPage("/");
3640
return;

src/loginAuthentication/LoginPage.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,35 @@ input:focus{
143143
align-items: center;
144144
background-color: rgba(255, 255, 255, 0.8);
145145
z-index: 1;
146+
}
147+
148+
/* Styling for Popup*/
149+
.popup-overlay {
150+
position: fixed;
151+
top: 0;
152+
left: 0;
153+
right: 0;
154+
bottom: 0;
155+
background: rgba(0, 0, 0, 0.5); /* Semi-transparent background */
156+
display: flex;
157+
justify-content: center;
158+
align-items: center;
159+
}
160+
161+
.popup {
162+
background: #fff;
163+
padding: 20px;
164+
border-radius: 8px;
165+
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
166+
text-align: center;
167+
max-width: 500px; /* Limit the max width */
168+
width: 100%;
169+
box-sizing: border-box;
170+
overflow-wrap: break-word;
171+
}
172+
173+
.popup button {
174+
margin-top: 10px;
175+
padding: 8px 16px;
176+
cursor: pointer;
146177
}

src/loginAuthentication/LoginPage.jsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {auth, provider} from "./firebase/FirebaseConfig";
99
import {signInWithPopup } from "firebase/auth";
1010
import {handleCreateUserWithEmailAndPassword, handleSignInWithEmailAndPassword} from './firebase/LoginAuthCreation';
1111
import ClipLoader from 'react-spinners/ClipLoader';
12+
import Popup from "../popup/Popup";
1213

1314
// for each time show the google accounts in the dialog
1415
provider.setCustomParameters({
@@ -24,7 +25,9 @@ function LoginPage(props) {
2425
const navigateToNextPage = useNavigate();
2526
const {setLoggedInUser} = props;
2627
const [isLoading, setIsLoading] = useState(false);
28+
const [showPopup, setShowPopup] = useState(false);
2729
const [isRegisterClicked, setRegisterClicked] = useState(false);
30+
const isReadInfoOnce = localStorage.getItem('isInfoRead') || false;
2831

2932
//password requirement
3033
const [isPwdFeedbackHint, setPwdFeedbackHint] = useState(null);
@@ -92,6 +95,16 @@ function LoginPage(props) {
9295
}, [input.password, handlePasswordErrorFeedback])
9396

9497

98+
// For show the popup initially
99+
useEffect(() => {
100+
const timer = setTimeout(() => {
101+
setShowPopup(true);
102+
}, 1500)
103+
104+
return () => clearTimeout(timer);
105+
}, [])
106+
107+
95108
// Login via username/password
96109
async function loginClicked(e) {
97110
e.preventDefault();
@@ -128,7 +141,6 @@ function LoginPage(props) {
128141

129142
// Register via username/password
130143
const registerClicked = async () => {
131-
132144
// validate username/email and password
133145
const isValidated = handleValidationForUserInput(input.username, input.password);
134146
if (!isValidated) return;
@@ -185,11 +197,10 @@ function LoginPage(props) {
185197
function googleLogin() {
186198
//signInWithRedirect(auth, provider) // alternative for Glogin
187199
signInWithPopup(auth, provider).then((data) => {
188-
storeLoginSuccessAndNavigate(data?.user)
200+
storeLoginSuccessAndNavigate(data?.user);
189201
}).catch((e) => {
190-
console.error("signinpopup catch--",e)
202+
console.error("signinpopup catch--", e);
191203
})
192-
193204
}
194205

195206
// Stored LoginStatus in localStorage and navigate to home
@@ -202,8 +213,8 @@ function LoginPage(props) {
202213
loggedInPhotoUrl: user?.photoURL || ""
203214
}
204215
localStorage.setItem("loggedInData", JSON.stringify(loginObj));
205-
setLoggedInUser(true)
206-
navigateToNextPage('/home')
216+
setLoggedInUser(true);
217+
navigateToNextPage('/home');
207218
}
208219

209220
// To show toast
@@ -215,10 +226,20 @@ function LoginPage(props) {
215226
}
216227
return;
217228
}
229+
230+
const closePopupInfo = (isRead = false) => {
231+
if(isRead) {
232+
setShowPopup(false);
233+
localStorage.setItem('isInfoRead', true);
234+
}
235+
}
218236

219237
return(
220238

221239
<div className="cover">
240+
{/* Popup shown initially */}
241+
{showPopup && !isReadInfoOnce && (<Popup setClosePopup={closePopupInfo}/>)}
242+
222243
<u><h2>{isRegisterClicked ? "Register Here " : "Login Here "}</h2></u>
223244
<p>{!isRegisterClicked ? "Sign in" : "Register here"} & let's get started</p>
224245
{errorMessageEmail.length > 0 && (<div className="error1">{errorMessageEmail}</div>)}

src/popup/Popup.jsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { APP_INITIAL_POPUP_MSG } from "../utility/constants";
2+
3+
4+
const Popup = (props) => {
5+
const { setClosePopup } = props;
6+
7+
const closePopup = () => {
8+
setClosePopup(true);
9+
}
10+
11+
return(
12+
<div className="popup-overlay">
13+
<div className="popup">
14+
<img src="favicon1.ico" alt='' />
15+
<p dangerouslySetInnerHTML={{__html: APP_INITIAL_POPUP_MSG}}></p>
16+
<button onClick={closePopup}>OK</button>
17+
</div>
18+
</div>
19+
);
20+
}
21+
export default Popup;

0 commit comments

Comments
 (0)