├── src ├── App.css ├── assets │ └── img │ │ ├── Loading.gif │ │ └── profile.jpg ├── Components │ ├── pages │ │ ├── Home │ │ │ ├── Home.jsx │ │ │ ├── Search.jsx │ │ │ └── Header │ │ │ │ ├── UserModal.jsx │ │ │ │ └── HomeHeader.jsx │ │ ├── Demo │ │ │ ├── Auth │ │ │ │ ├── Trending.jsx │ │ │ │ ├── Banner.jsx │ │ │ │ ├── Discover.jsx │ │ │ │ ├── SignIn.jsx │ │ │ │ ├── SignUp.jsx │ │ │ │ └── Auth.jsx │ │ │ ├── Demo.jsx │ │ │ └── DemoHeader.jsx │ │ └── Profile │ │ │ ├── Activites │ │ │ ├── ProfileList.jsx │ │ │ ├── ProfileAbout.jsx │ │ │ └── ProfileHome.jsx │ │ │ ├── Profile.jsx │ │ │ └── EditProfile.jsx │ ├── Loading │ │ └── Loading.jsx │ ├── common │ │ └── Posts │ │ │ └── Posts.jsx │ └── Context │ │ └── Context.jsx ├── utils │ ├── Modal.jsx │ ├── Input.jsx │ └── Helper.js ├── index.css ├── main.jsx ├── App.jsx ├── Firebase │ └── Firebase-config.js └── data.js ├── postcss.config.js ├── vite.config.js ├── .gitignore ├── index.html ├── README.md ├── .eslintrc.cjs ├── tailwind.config.js ├── package.json └── public └── vite.svg /src/App.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/Loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alirazaramejo/meduim-blog/HEAD/src/assets/img/Loading.gif -------------------------------------------------------------------------------- /src/assets/img/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alirazaramejo/meduim-blog/HEAD/src/assets/img/profile.jpg -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/Components/pages/Home/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function Home() { 4 | return ( 5 |
Home
6 | ) 7 | } 8 | 9 | export default Home -------------------------------------------------------------------------------- /src/Components/pages/Demo/Auth/Trending.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function Trending() { 4 | return ( 5 |
Trending
6 | ) 7 | } 8 | 9 | export default Trending -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /src/Components/pages/Profile/Activites/ProfileList.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function ProfileList() { 4 | return ( 5 |
ProfileList
6 | ) 7 | } 8 | 9 | export default ProfileList -------------------------------------------------------------------------------- /src/Components/Loading/Loading.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import loadingImg from "../../assets/img/Loading.gif"; 3 | 4 | function Loading() { 5 | return ( 6 |
7 | loading 8 |
9 | ); 10 | } 11 | 12 | export default Loading; 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/utils/Modal.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Modal = ({ children, modal, setModal }) => { 4 | return ( 5 | <> 6 |
setModal(false)} 8 | className={`bg-white/50 fixed inset-0 z-10 9 | ${ 10 | modal ? "visible opacity-100" : "invisible opacity-0" 11 | } transition-all duration-500`} 12 | /> 13 | {children} 14 | 15 | ); 16 | }; 17 | 18 | export default Modal; 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | *{ 6 | @apply m-0 p-0 box-border; 7 | } 8 | body{ 9 | @apply font-texts; 10 | } 11 | .size{ 12 | @apply w-[95%] md:w-[90%] mx-auto; 13 | } 14 | .shadows{ 15 | box-shadow:0px 0px 3px 0.3px rgb(182,182,182); 16 | } 17 | .btn{ 18 | @apply px-3 p-2 text-sm font-medium; 19 | } 20 | .center{ 21 | position: fixed; 22 | top: 50%; 23 | left: 50%; 24 | transform: translate(-50%,-50%); 25 | } 26 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App.jsx'; 4 | import './index.css'; 5 | import 'react-toastify/dist/ReactToastify.css'; 6 | import { BrowserRouter } from 'react-router-dom'; 7 | import Context from './Components/Context/Context.jsx'; 8 | 9 | ReactDOM.createRoot(document.getElementById('root')).render( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | -------------------------------------------------------------------------------- /src/utils/Input.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function Input({ type, title, form, setForm }) { 4 | const handleChange = (e) => { 5 | setForm({ ...form, [e.target.name]: e.target.value }); 6 | }; 7 | 8 | return ( 9 |
10 | 11 | 17 |
18 | ); 19 | } 20 | 21 | export default Input; 22 | -------------------------------------------------------------------------------- /src/Components/pages/Profile/Activites/ProfileAbout.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function ProfileAbout({getAllUsersData,setEditModal}) { 4 | return ( 5 |
6 |

7 | {getAllUsersData?.bio ? getAllUsersData.username : "Hasn't added a bio yet."} 8 |

9 |
10 | 13 |
14 |
15 | ) 16 | } 17 | 18 | export default ProfileAbout -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react/jsx-no-target-blank': 'off', 16 | 'react-refresh/only-export-components': [ 17 | 'warn', 18 | { allowConstantExport: true }, 19 | ], 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /src/Components/pages/Demo/Demo.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Banner from './Auth/Banner'; 3 | import Trending from './Auth/Trending'; 4 | import Posts from '../../common/Posts/Posts'; 5 | import Discover from './Auth/Discover'; 6 | 7 | function Demo() { 8 | return ( 9 | <> 10 | 11 | 12 |
13 |
14 | 15 |
16 |
17 | 18 |
19 |
20 | 21 | ); 22 | } 23 | 24 | export default Demo; 25 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | /** @type {import('tailwindcss').Config} */ 3 | export default { 4 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 5 | theme: { 6 | extend: { 7 | colors: { 8 | black1: "rgba(0,0,0,0.8)", 9 | banner: "rgb(255, 192, 23)", 10 | }, 11 | fontFamily: { 12 | title: `gt-super, Georgia, Cambria,Times New Roman, Times, serif;`, 13 | texts: `sohne, Helvetica Neue, Helvetica, Arial, sans-serif`, 14 | }, 15 | gridTemplateColumns: { 16 | card: "repeat(auto-fit, minmax(280px, 1fr))", 17 | }, 18 | }, 19 | }, 20 | plugins: [], 21 | }; -------------------------------------------------------------------------------- /src/Components/pages/Demo/Auth/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import reactImg from '../../../../assets/react.svg'; 3 | 4 | function Banner() { 5 | return ( 6 |
7 |
8 | {/* Main heading */} 9 |

Stay curious.

10 | {/* Subheading */} 11 |

12 | Discover stories, thinking, and expertise from writers on any topic. 13 |

14 | {/* Button */} 15 | 18 |
19 |
20 | ); 21 | } 22 | 23 | export default Banner; 24 | -------------------------------------------------------------------------------- /src/utils/Helper.js: -------------------------------------------------------------------------------- 1 | export const secretEmail = (email) => { 2 | const [username, domain] = email.split("@"); 3 | const secretUser = username.substring(0, 2) + "*".repeat(username.length - 2); 4 | return `${secretUser}@${domain}`; 5 | }; 6 | 7 | export const readTime = (desc) => { 8 | const averageReading = 225; 9 | 10 | const div = document.createElement("div"); 11 | div.innerHTML = desc.__html; 12 | 13 | const textContext = div.textContent || div.innerHTML; 14 | const words = textContext.trim().split(/\s+/); 15 | return Math.ceil(words.length / averageReading); 16 | }; 17 | 18 | export const formatNum = (num) => { 19 | if (num >= 1e9) { 20 | return (num / 1e9).toFixed(1) + "B"; 21 | } else if (num >= 1e6) { 22 | return (num / 1e6).toFixed(1) + "M"; 23 | } else if (num >= 1e3) { 24 | return (num / 1e3).toFixed(1) + "K"; 25 | } else { 26 | return num.toString(); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "medium", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "firebase": "^10.8.0", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0", 16 | "react-icons": "^5.0.1", 17 | "react-router-dom": "^6.22.0", 18 | "react-toastify": "^10.0.4" 19 | }, 20 | "devDependencies": { 21 | "@types/react": "^18.2.55", 22 | "@types/react-dom": "^18.2.19", 23 | "@vitejs/plugin-react": "^4.2.1", 24 | "autoprefixer": "^10.4.17", 25 | "eslint": "^8.56.0", 26 | "eslint-plugin-react": "^7.33.2", 27 | "eslint-plugin-react-hooks": "^4.6.0", 28 | "eslint-plugin-react-refresh": "^0.4.5", 29 | "postcss": "^8.4.35", 30 | "tailwindcss": "^3.4.1", 31 | "vite": "^5.1.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Navigate, Route, Routes } from 'react-router-dom'; 3 | import Home from './Components/pages/Home/Home'; 4 | import Demo from './Components/pages/Demo/Demo'; 5 | import HomeHeader from './Components/pages/Home/Header/HomeHeader'; 6 | import DemoHeader from './Components/pages/Demo/DemoHeader'; 7 | import { ToastContainer } from 'react-toastify'; 8 | import { Blog } from './Components/Context/Context'; 9 | import Profile from './Components/pages/Profile/Profile'; 10 | function App() { 11 | const { currentUser } = Blog(); 12 | 13 | return ( 14 | <> 15 | {currentUser ? : } 16 | 17 | 18 | {currentUser && } />} 19 | {!currentUser && } />} 20 | } /> 21 | } /> 22 | 23 | 24 | ); 25 | } 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /src/Components/pages/Home/Search.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Modal from "../../../utils/Modal"; 3 | import { CiSearch } from "react-icons/ci"; 4 | function Search({ modal, setModal }) { 5 | return ( 6 | <> 7 | 8 |
15 |
16 | 17 | 18 | 19 | 24 |
25 |
26 |
27 | 28 | ); 29 | } 30 | 31 | export default Search; 32 | -------------------------------------------------------------------------------- /src/Firebase/Firebase-config.js: -------------------------------------------------------------------------------- 1 | // Import the functions you need from the SDKs you need 2 | import { initializeApp } from "firebase/app"; 3 | import { getAuth,GoogleAuthProvider } from "firebase/auth"; 4 | import { getStorage, ref, uploadBytes, getDownloadURL } from "firebase/storage"; // Import getDownloadURL 5 | import { getFirestore, doc } from "firebase/firestore"; 6 | const firebaseConfig = { 7 | apiKey: "AIzaSyAQjlwhuwWYJ-OdhhPP4XRxEgWSfQ5d3-o", 8 | authDomain: "ali-raza-518df.firebaseapp.com", 9 | databaseURL: "https://ali-raza-518df-default-rtdb.firebaseio.com", 10 | projectId: "ali-raza-518df", 11 | storageBucket: "ali-raza-518df.appspot.com", 12 | messagingSenderId: "308309137877", 13 | appId: "1:308309137877:web:ac0be37dd3c2bb9544055c", 14 | measurementId: "G-82NM2JZS9D" 15 | }; 16 | 17 | // Initialize Firebase 18 | const app = initializeApp(firebaseConfig); 19 | export const auth = getAuth(); 20 | export const provider = new GoogleAuthProvider(); 21 | export const storage = getStorage(); 22 | export const db = getFirestore(app); 23 | export { doc }; 24 | export { ref, uploadBytes, getDownloadURL }; 25 | -------------------------------------------------------------------------------- /src/Components/pages/Profile/Activites/ProfileHome.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function ProfileHome() { 4 | return ( 5 |
6 |

aaa

7 |

aaa

8 |

aaa

9 |

aaa

10 |

aaa

11 |

aaa

12 |

aaa

13 |

aaa

14 |

aaa

15 |

aaa

16 |

aaa

17 |

aaa

18 |

aaa

19 |

aaa

20 |

aaa

21 |

aaa

22 |

aaa

23 |

aaa

24 |

aaa

25 |

aaa

26 |

aaa

27 |

aaa

28 |

aaa

29 |

aaa

30 |

aaa

31 |

aaa

32 |

aaa

33 |

aaa

34 |

aaa

35 |

aaa

36 |

aaa

37 |

aaa

38 |

aaa

39 |

aaa

40 |

aaa

41 |

aaa

42 |

aaa

43 |

aaa

44 |

aaa

45 |

aaa

46 |

aaa

47 |

aaa

48 |

aaa

49 |

aaa

50 |

aaa

51 |

aaa

52 |

aaa

53 |

aaa

54 |
55 | ) 56 | } 57 | 58 | export default ProfileHome -------------------------------------------------------------------------------- /src/Components/pages/Demo/Auth/Discover.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { discover, discoverActions } from '../../../../data'; 3 | 4 | function Discover() { 5 | return ( 6 |
7 | {/* Discover topics section */} 8 |
9 |

Discover more of what matters to you

10 |
11 | {/* Mapping over discover topics */} 12 | {discover.map((item, i) => ( 13 | 16 | ))} 17 |
18 | {/* Button to see more topics */} 19 | 20 |
21 | {/* Discover actions section */} 22 |
23 | {/* Mapping over discover actions */} 24 | {discoverActions.map((item, i) => ( 25 | 26 | ))} 27 |
28 |
29 | ); 30 | } 31 | 32 | export default Discover; 33 | -------------------------------------------------------------------------------- /src/Components/common/Posts/Posts.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function Posts() { 4 | return ( 5 |
6 |

post

7 |

post

8 |

post

9 |

post

10 |

post

11 |

post

12 |

post

13 |

post

14 |

post

15 |

post

16 |

post

17 |

post

18 |

post

19 |

post

20 |

post

21 |

post

22 |

post

23 |

post

24 |

post

25 |

post

26 |

post

27 |

post

28 |

post

29 |

post

30 |

post

31 |

post

32 |

post

33 |

post

34 |

post

35 |

post

36 |

post

37 |

post

38 |

post

39 |

post

40 |

post

41 |

post

42 |

post

43 |

post

44 |

post

45 |

post

46 |

post

47 |

post

48 |

post

49 |

post

50 |

post

51 |

post

52 |

post

53 |

post

54 |

post

55 |

post

56 |

post

57 |

post

58 |
59 | ) 60 | } 61 | 62 | export default Posts -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Components/Context/Context.jsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useContext, useEffect, useState } from 'react'; 2 | import { auth, db } from '../../Firebase/Firebase-config'; // Assuming db is your Firestore instance 3 | import LoadingIndicator from '../Loading/Loading'; 4 | import { onAuthStateChanged } from 'firebase/auth'; 5 | import { collection, query, onSnapshot } from 'firebase/firestore'; 6 | 7 | const BlogContext = createContext(); 8 | 9 | function Context({ children }) { 10 | const [currentUser, setCurrentUser] = useState(null); 11 | const [loading, setLoading] = useState(true); 12 | const [allUsers, setAllUsers] = useState([]); 13 | const [userLoading, setUserLoading] = useState(true); 14 | useEffect(() => { 15 | const unsubscribe = onAuthStateChanged(auth, (user) => { 16 | setCurrentUser(user); 17 | setLoading(false); 18 | }); 19 | 20 | return unsubscribe; // return the unsubscribe function to clean up 21 | }, []); // no need to include currentUser in dependencies 22 | 23 | useEffect(() => { 24 | const getUsers = () => { 25 | const usersRef = collection(db, 'users'); 26 | const q = query(usersRef); 27 | 28 | const unsubscribe = onSnapshot(q, (snapshot) => { 29 | setAllUsers(snapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id }))); 30 | setUserLoading(false); 31 | }); 32 | 33 | return unsubscribe; // return the unsubscribe function to clean up 34 | }; 35 | 36 | getUsers(); 37 | }, []); // empty dependency array to run only once when component mounts 38 | 39 | // console.log(allUsers); 40 | 41 | return ( 42 | 43 | {loading ? : children} 44 | 45 | ); 46 | } 47 | 48 | export default Context; 49 | 50 | export const Blog = () => useContext(BlogContext); 51 | -------------------------------------------------------------------------------- /src/Components/pages/Demo/DemoHeader.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | import { nav } from "../../../data.js"; 4 | import Auth from './Auth/Auth.jsx'; 5 | 6 | function DemoHeader() { 7 | const [colorActive, setColorActive] = useState(false); 8 | const [modal, setModal] = useState(false); 9 | 10 | useEffect(() => { 11 | const scrollHandler = () => { 12 | window.scrollY > 480 ? setColorActive(true) : setColorActive(false); 13 | } 14 | 15 | window.addEventListener('scroll', scrollHandler); 16 | 17 | // Cleanup function 18 | return () => { 19 | window.removeEventListener('scroll', scrollHandler); 20 | }; 21 | }, []); 22 | 23 | return ( 24 |
25 |
26 | 27 | logo 28 | 29 |
30 |
31 | {nav.map((link, i) => ( 32 | {link.title} 33 | ))} 34 |
35 | 36 | 37 |
38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 | ); 46 | } 47 | 48 | export default DemoHeader; 49 | -------------------------------------------------------------------------------- /src/Components/pages/Demo/Auth/SignIn.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import Input from "../../../../utils/Input"; 3 | import { toast } from "react-toastify"; 4 | import { MdKeyboardArrowLeft } from "react-icons/md"; 5 | import { signInWithEmailAndPassword } from "firebase/auth"; 6 | import { auth } from "../../../../Firebase/Firebase-config"; 7 | import { useNavigate } from "react-router-dom"; 8 | 9 | function SignIn({ setSignReq }) { 10 | const Navigate = useNavigate(); 11 | const [form, setForm] = useState({ 12 | email: "", 13 | password: "", 14 | }); 15 | const [loading, setLoading] = useState(false); 16 | 17 | const handleSubmit = async (e) => { 18 | e.preventDefault(); 19 | if (form.email === "" || form.password === "") { 20 | toast.error("All fields are required!!"); 21 | return; 22 | } 23 | try { 24 | setLoading(true); 25 | await signInWithEmailAndPassword(auth, form.email, form.password); 26 | Navigate("/"); 27 | toast.success("User has been logged in successfully"); 28 | } catch (error) { 29 | toast.error(error.message); 30 | } finally { 31 | setLoading(false); 32 | } 33 | }; 34 | 35 | return ( 36 |
37 |

Sign In with email

38 |

39 | Enter the email address associated with your account, and we’ll send a 40 | magic link to your inbox. 41 |

42 |
43 | 44 | 45 | 51 |
52 | 58 |
59 | ); 60 | } 61 | 62 | export default SignIn; 63 | -------------------------------------------------------------------------------- /src/Components/pages/Home/Header/UserModal.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { LiaUserSolid } from "react-icons/lia"; 3 | import { MdLocalLibrary } from "react-icons/md"; // Changed from MdOutlineLocalLibrary 4 | import { BiSpreadsheet } from "react-icons/bi"; 5 | import { HiOutlineChartBar } from "react-icons/hi"; 6 | import { LiaEditSolid } from "react-icons/lia"; 7 | import { Blog } from "../../../Context/Context"; 8 | import { Link } from "react-router-dom"; 9 | import { secretEmail } from "../../../../utils/Helper"; 10 | import { signOut } from "firebase/auth"; 11 | 12 | import { toast } from "react-toastify"; 13 | 14 | function UserModal({ setModal }) { 15 | const { currentUser } = Blog(); 16 | const userModal = [ 17 | { 18 | title: "Profile", 19 | icon: , 20 | path: `/profile/${currentUser?.uid}`, 21 | }, 22 | { 23 | title: "Library", 24 | icon: , // Changed from MdOutlineLocalLibrary 25 | path: "/library", 26 | }, 27 | { 28 | title: "Stories", 29 | icon: , 30 | path: "/stories", 31 | }, 32 | { 33 | title: "Stats", 34 | icon: , 35 | path: "/stats", 36 | }, 37 | ]; 38 | 39 | const logout = () => { 40 | signOut().then(() => { 41 | toast.success("Logged out successfully!"); 42 | setModal(false); 43 | }).catch(error => { 44 | toast.error(error.message); 45 | }); 46 | }; 47 | 48 | return ( 49 |
52 | 55 | 56 | 57 | 58 | Write 59 | 60 |
61 | {userModal.map((link, i) => ( 62 | setModal(false)} 64 | className="flex items-center gap-2 text-gray-500 hover:text-black/70" 65 | key={i} 66 | to={link.path}> 67 | {link.icon} 68 |

{link.title}

69 | 70 | ))} 71 |
72 | 78 |
79 | ); 80 | } 81 | 82 | export default UserModal; 83 | -------------------------------------------------------------------------------- /src/Components/pages/Home/Header/HomeHeader.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { BsMedium } from "react-icons/bs"; 3 | import { CiSearch } from "react-icons/ci"; 4 | import { RiEditCircleLine } from "react-icons/ri"; 5 | import { IoMdNotificationsOutline } from "react-icons/io"; 6 | import { MdKeyboardArrowDown } from "react-icons/md"; 7 | import { Link } from 'react-router-dom'; 8 | import Modal from "../../../../utils/Modal"; 9 | import Search from '../Search'; 10 | import UserModal from './UserModal'; 11 | import Profile from "../../../../assets/img/profile.jpg"; 12 | import { Blog } from '../../../Context/Context'; 13 | import Loading from '../../../Loading/Loading'; 14 | 15 | function HomeHeader() { 16 | const { currentUser, allUsers, userLoading } = Blog(); // Destructuring Blog context 17 | const [modal, setModal] = useState(false); 18 | const [search, setSearch] = useState(false); 19 | const [userData, setUserData] = useState(null); 20 | 21 | useEffect(() => { 22 | if (!userLoading && currentUser && allUsers.length > 0) { 23 | const getUserData = allUsers.find((user) => user.id === currentUser.uid); 24 | setUserData(getUserData); 25 | } 26 | }, [userLoading, currentUser, allUsers]); 27 | 28 | return ( 29 |
30 | {userLoading && } 31 |
32 | {/* left side div */} 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | {/* right side div we make */} 42 |
43 | setSearch(true)} className='flex sm:hidden text-3xl text-gray-100 cursor-pointer'> 44 | 45 | 46 | Write 47 | 48 | 49 | 50 |
51 | setModal(true)} className='w-[2.3rem] h-[2.3rem] object-cover rounded-full cursor-pointer' src={userData?.userImg ? userData.userImg : Profile} alt="Profile Image" /> 52 | 53 | 54 | 55 | 56 |
57 | 58 |
59 |
60 |
61 |
62 |
63 |
64 | ); 65 | } 66 | 67 | export default HomeHeader; 68 | -------------------------------------------------------------------------------- /src/Components/pages/Demo/Auth/SignUp.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import Input from "../../../../utils/Input"; 3 | import { MdKeyboardArrowLeft } from "react-icons/md"; 4 | import { toast } from "react-toastify"; 5 | import { createUserWithEmailAndPassword } from "firebase/auth"; 6 | import { auth, db } from "../../../../Firebase/Firebase-config"; 7 | import { useNavigate } from "react-router-dom"; 8 | import { doc, getDoc, setDoc } from "firebase/firestore"; 9 | 10 | const SignUp = ({ setSignReq, setModal }) => { 11 | const navigate = useNavigate(); 12 | const [loading, setLoading] = useState(false); 13 | const [form, setForm] = useState({ 14 | username: "", 15 | email: "", 16 | password: "", 17 | rePassword: "", 18 | }); 19 | 20 | const handleSubmit = async (e) => { 21 | e.preventDefault(); 22 | if (form[("username", "email", "password", "rePassword")] === "") { 23 | toast.error("All fields are required"); 24 | } else if (form["password"] !== form["rePassword"]) { 25 | toast.error("Your passwords are not matching!!"); 26 | return; 27 | } else { 28 | setLoading(true); 29 | const { user } = await createUserWithEmailAndPassword( 30 | auth, 31 | form.email, 32 | form.password 33 | ); 34 | 35 | const ref = doc(db, "users", user.uid); 36 | const userDoc = await getDoc(ref); 37 | 38 | if (!userDoc.exists()) { 39 | await setDoc(ref, { 40 | userId: user.uid, 41 | username: form.username, 42 | email: form.email, 43 | userImg: "", 44 | bio: "", 45 | created: Date.now(), 46 | }); 47 | navigate("/"); 48 | toast.success("New Account has been Created"); 49 | setModal(false); 50 | setLoading(false); 51 | } 52 | } 53 | }; 54 | 55 | return ( 56 |
57 |

Sign up with email

58 |

59 | Enter the email address associated with your account, and we’ll send a 60 | magic link to your inbox. 61 |

62 |
63 | 64 | 65 | 66 | 72 | 78 |
79 | 86 |
87 | ); 88 | }; 89 | 90 | export default SignUp; 91 | -------------------------------------------------------------------------------- /src/Components/pages/Profile/Profile.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import ProfileAbout from "./Activites/ProfileAbout"; 3 | import ProfileList from "./Activites/ProfileList"; 4 | import ProfileHome from "./Activites/ProfileHome"; 5 | import Modal from "../../../utils/Modal"; 6 | import { LiaTimesSolid } from "react-icons/lia"; 7 | import { IoSettingsSharp } from "react-icons/io5"; 8 | import profileImg from "../../../assets/img/profile.jpg"; 9 | import { discoverActions } from "../../../data"; 10 | 11 | import EditProfile from "./EditProfile"; 12 | import { Blog } from "../../Context/Context"; 13 | import { useParams } from "react-router-dom"; 14 | 15 | function Profile() { 16 | const {allUsers} = Blog(); 17 | const {userId} = useParams(); 18 | const activity = [ 19 | { title: "Home", comp: ProfileHome }, 20 | { title: "Lists", comp: ProfileList }, 21 | { title: "About", comp: ProfileAbout }, 22 | ]; 23 | 24 | const [currentActive, setCurrentActive] = useState(activity[0]); 25 | const [modal, setModal] = useState(false); 26 | 27 | const [editModal, setEditModal] = useState(false); 28 | const getAllUsersData = allUsers.find((user) => user.id === userId); 29 | console.log("all data", getAllUsersData); 30 | return ( 31 |
32 | {/* User activity */} 33 |
34 |
35 |

36 | {getAllUsersData?.username || "Ali Raza"} 37 |

38 |

Followers(2)

39 |

Following(2)

40 |
41 |
42 | {activity.map((item, index) => ( 43 |
51 | 54 |
55 | ))} 56 |
57 | 58 |
59 | {/* btn add to close and open side bar */} 60 | 66 | {/* User Full details here */} 67 | 68 |
74 | {/* Icons make to close the profile */} 75 |
76 | 82 |
83 | {/* Profile details make */} 84 |
85 | profile-Img 90 |

Ali Raza

91 |

92 | I am Ali Raza 93 |

94 | 95 | 102 | {/* Nav data from datajs file get */} 103 |
104 | {discoverActions.map((item, index) => ( 105 | 108 | ))} 109 |
110 |
111 |
112 |
113 | {editModal && ( 114 | 115 | )} 116 |
117 | ); 118 | } 119 | 120 | export default Profile; 121 | -------------------------------------------------------------------------------- /src/Components/pages/Demo/Auth/Auth.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { LiaTimesSolid } from "react-icons/lia"; 3 | import { FcGoogle } from "react-icons/fc"; 4 | import { MdFacebook } from "react-icons/md"; 5 | import { AiOutlineMail } from "react-icons/ai"; 6 | import { FaApple } from "react-icons/fa"; 7 | import { BsTwitterX } from "react-icons/bs"; 8 | import { signInWithPopup } from "firebase/auth"; 9 | import { doc, getDoc, setDoc } from "firebase/firestore"; 10 | import { toast } from "react-toastify"; 11 | import { Navigate } from "react-router-dom"; 12 | import SignUp from "../Auth/SignUp" 13 | import SignIn from "../Auth/SignIn" 14 | 15 | import Modal from "../../../../utils/Modal"; 16 | import { auth, db, provider } from "../../../../Firebase/Firebase-config"; 17 | 18 | function Auth({ modal, setModal }) { 19 | const [createUser, setCreateUser] = useState(false); 20 | const [signReq, setSignReq] = useState(""); 21 | 22 | // Function to handle Google authentication 23 | const GoogleAuth = async () => { 24 | try { 25 | const userCredential = await signInWithPopup(auth, provider); 26 | const newUser = userCredential.user; 27 | const ref = doc(db, "users", newUser.uid); 28 | const userDoc = await getDoc(ref); 29 | if (!userDoc.exists()) { 30 | await setDoc(ref, { 31 | userId: newUser.uid, 32 | username: newUser.displayName, 33 | email: newUser.email, 34 | userImg: newUser.photoURL, 35 | bio: "", 36 | }); 37 | Navigate("/"); // Redirect to home page 38 | setModal(false); // Close the modal 39 | toast.success("Sign in with Google successful"); 40 | } 41 | } catch (error) { 42 | toast.error("Error signing in with Google: " + error.message); 43 | } 44 | }; 45 | 46 | // CSS class to control visibility of the modal 47 | const hidden = modal ? "visible opacity-100" : "invisible opacity-0"; 48 | 49 | return ( 50 |
75 |

76 | {createUser ? "Already have an account?" : "No Account?"} 77 | 80 |

81 | 82 | ) : signReq === "sign-In" ? ( 83 | // Show sign-in form 84 | 85 | ) : signReq === "sign-up" ? ( 86 | // Show sign-up form 87 | 88 | ) : null} 89 | {!createUser && ( 90 | // Forgot password or sign-in trouble message 91 |

92 | Forgot email or trouble signing in? 93 |

94 | )} 95 |

96 | {`Click ${createUser ? "Sign In" : "Sign Up"} to agree to Medium’s Terms of Service and acknowledge that Medium’s Privacy Policy applies to you.`} 97 |

98 | 99 | 100 | 101 | ); 102 | } 103 | 104 | // Button component 105 | const Button = ({ icon, text, click }) => { 106 | return ( 107 | 110 | ); 111 | }; 112 | 113 | export default Auth; 114 | -------------------------------------------------------------------------------- /src/Components/pages/Profile/EditProfile.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState, useEffect } from "react"; 2 | import Modal from "../../../utils/Modal"; 3 | import { FaTimes } from "react-icons/fa"; 4 | import profileImg from "../../../assets/img/profile.jpg"; 5 | import { storage, db, uploadBytes, getDownloadURL, ref, doc } from "../../../Firebase/Firebase-config.js"; 6 | import { toast } from "react-toastify"; 7 | import { updateDoc } from "firebase/firestore"; 8 | 9 | function EditProfile({ editModal, setEditModal, getAllUsersData }) { 10 | const imgReference = useRef(null); 11 | const [imgURL, setImgURL] = useState(""); 12 | const [loading, setLoading] = useState(false); 13 | const [form, setForm] = useState({ 14 | username: "", 15 | bio: "", 16 | userImg: "" 17 | }); 18 | 19 | const openFile = () => { 20 | imgReference.current.click(); 21 | }; 22 | 23 | const buttonStyle = "border border-gray-600 py-2 px-5 rounded-full text-green-600"; 24 | 25 | useEffect(() => { 26 | if (getAllUsersData) { 27 | setForm({ 28 | username: getAllUsersData.username, 29 | bio: getAllUsersData.bio, 30 | userImg: getAllUsersData.userImg, 31 | }); 32 | } 33 | }, [getAllUsersData]); 34 | 35 | const saveForm = async () => { 36 | if (form.username.length < 1 || form.bio.length < 1) { 37 | toast.error("Please fill all the fields"); 38 | return; 39 | } 40 | setLoading(true); 41 | const storageRef = ref(storage, `usersImg/${form.username}`); 42 | await uploadBytes(storageRef, form?.userImg); 43 | const imageURL = await getDownloadURL(storageRef); 44 | try { 45 | const uploadDocRef = doc(db, "users", getAllUsersData.id); 46 | await updateDoc(uploadDocRef, { 47 | username: form.username, 48 | bio: form.bio, 49 | userImg: imgURL ? imageURL : form.userImg 50 | }); 51 | toast.success("Profile Updated"); 52 | setLoading(false); 53 | setEditModal(false); 54 | } catch (error) { 55 | toast.error("Something went wrong"); 56 | } 57 | }; 58 | 59 | return ( 60 | 61 |
62 |
63 |

Profile Information

64 | 67 |
68 |
69 |

Photo

70 |
71 |
72 | image 77 | { 79 | setImgURL(URL.createObjectURL(e.target.files[0])); 80 | setForm({ ...form, userImg: e.target.files[0] }); 81 | }} 82 | accept="image/jpg, image/png, image/jpeg" 83 | ref={imgReference} 84 | type="file" 85 | hidden 86 | /> 87 |
88 |
89 |
90 | 93 | 94 |
95 |

96 | Recommended: Square JPG, PNG, or GIF, at least 1000 pixels per side 97 |

98 |
99 |
100 |
101 |
102 | 105 | setForm({ ...form, username: e.target.value })} 107 | value={form.username} 108 | type="text" 109 | className="p-1 border-black w-full outline-none" 110 | placeholder="Username..." 111 | maxLength={50} 112 | /> 113 |

114 | Appears on your Profile page, as your byline, and in your responses. {form.username.length}/50 115 |

116 |
117 | 120 | setForm({ ...form, bio: e.target.value })} 122 | value={form.bio} 123 | type="text" 124 | className="p-1 border-black w-full outline-none" 125 | placeholder="Bio..." 126 | maxLength={50} 127 | /> 128 |

129 | Appears on your Profile and next to your stories. {form.bio.length}/160 130 |

131 |
132 |
133 |
134 | 137 | 140 |
141 |
142 |
143 | ); 144 | } 145 | 146 | export default EditProfile; 147 | -------------------------------------------------------------------------------- /src/data.js: -------------------------------------------------------------------------------- 1 | export const nav = [ 2 | { 3 | title: "Our story", 4 | path: "/", 5 | }, 6 | { 7 | title: "Membership", 8 | path: "/", 9 | }, 10 | { 11 | title: "Write", 12 | path: "/", 13 | }, 14 | ]; 15 | 16 | export const discover = [ 17 | "Technology", 18 | "Study", 19 | "Programming", 20 | "Sport", 21 | "Knowledge", 22 | "Self Improvement", 23 | "Relationships", 24 | "Machine Learning", 25 | "Politics", 26 | ]; 27 | 28 | export const discoverActions = [ 29 | "Help", 30 | "Status", 31 | "Writers", 32 | "Blog", 33 | "Careers", 34 | "Privacy", 35 | "Terms", 36 | "About", 37 | "Text to speech", 38 | "Teams", 39 | ]; 40 | 41 | export const recommendedPosts = [ 42 | { 43 | postId: 1, 44 | user: "Tara Haelle", 45 | title: 46 | "We’re starting to understand more of what causes long COVID brain fog", 47 | subtitle: "Do this instead", 48 | desc: `Not only did a new study identify two blood proteins linked to cognitive difficulties a year 49 | after COVID-19 infection, but the What is Lorem Ipsum? 50 | Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the 51 | industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type 52 | and scrambled it to make a type specimen book. It has survived not only five centuries, but also 53 | the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 54 | 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with 55 | desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. 56 | Why do we use it? 57 | It is a long established fact that a reader will be distracted by the readable content of a page 58 | when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal 59 | distribution of letters, as opposed to using 'Content here, content here', making it look like 60 | readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as 61 | their default model text, and a search for 'lorem ipsum' will uncover many web sites still in 62 | their infancy. Various versions have evolved over the years, sometimes by accident, sometimes 63 | on purpose (injected humour and the like). 64 | Where does it come from? 65 | Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of 66 | classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a 67 | Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin 68 | words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in 69 | classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10 70 | .32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, 71 | written in 45 BC. This book is a treatise on the theory of ethics, very popular during the 72 | Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a 73 | line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. 74 | Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced 75 | in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.`, 76 | date: `Sep 13`, 77 | readTime: "7 min read", 78 | postImg: 79 | "https://miro.medium.com/v2/resize:fill:300:201/1*6nZUT6CkYE1frUF8eAVphw.jpeg", 80 | userImg: 81 | "https://fiverr-res.cloudinary.com/images/t_main1,q_auto,f_auto,q_auto,f_auto/gigs/142819271/original/09dafa4104fa6aeca4e62f33326be4933ae7ccac/create-cartoon-profile-picture-abd7.jpg", 82 | }, 83 | { 84 | postId: 2, 85 | user: "Tara Haelle", 86 | title: 87 | "We’re starting to understand more of what causes long COVID brain fog", 88 | subtitle: "Do this instead", 89 | desc: `Not only did a new study identify two blood proteins linked to cognitive difficulties a year 90 | after COVID-19 infection, but the What is Lorem Ipsum? 91 | Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the 92 | industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type 93 | and scrambled it to make a type specimen book. It has survived not only five centuries, but also 94 | the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 95 | 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with 96 | desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. 97 | Why do we use it? 98 | It is a long established fact that a reader will be distracted by the readable content of a page 99 | when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal 100 | distribution of letters, as opposed to using 'Content here, content here', making it look like 101 | readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as 102 | their default model text, and a search for 'lorem ipsum' will uncover many web sites still in 103 | their infancy. Various versions have evolved over the years, sometimes by accident, sometimes 104 | on purpose (injected humour and the like). 105 | Where does it come from? 106 | Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of 107 | classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a 108 | Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin 109 | words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in 110 | classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10 111 | .32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, 112 | written in 45 BC. This book is a treatise on the theory of ethics, very popular during the 113 | Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a 114 | line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. 115 | Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced 116 | in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.`, 117 | date: `Sep 13`, 118 | readTime: "7 min read", 119 | postImg: 120 | "https://miro.medium.com/v2/resize:fill:300:201/1*6nZUT6CkYE1frUF8eAVphw.jpeg", 121 | userImg: 122 | "https://fiverr-res.cloudinary.com/images/t_main1,q_auto,f_auto,q_auto,f_auto/gigs/142819271/original/09dafa4104fa6aeca4e62f33326be4933ae7ccac/create-cartoon-profile-picture-abd7.jpg", 123 | }, 124 | ]; 125 | 126 | export const users = [ 127 | { 128 | userId: 1, 129 | username: "Benjamin Marie", 130 | bio: "Ph.D, research scientist in NLP/AI", 131 | userImg: 132 | "https://i.pinimg.com/736x/72/ea/af/72eaaf5c70436356bce53862c75c7eeb.jpg", 133 | }, 134 | { 135 | userId: 2, 136 | username: "Benjamin Marie", 137 | bio: "Ph.D, research scientist in NLP/AI", 138 | userImg: 139 | "https://i.pinimg.com/736x/72/ea/af/72eaaf5c70436356bce53862c75c7eeb.jpg", 140 | }, 141 | { 142 | userId: 3, 143 | username: "Benjamin Marie", 144 | bio: "Ph.D, research scientist in NLP/AI", 145 | userImg: 146 | "https://i.pinimg.com/736x/72/ea/af/72eaaf5c70436356bce53862c75c7eeb.jpg", 147 | }, 148 | ]; 149 | 150 | export const comments = [ 151 | { 152 | id: 1, 153 | username: "username", 154 | userImg: 155 | "https://i.pinimg.com/736x/72/ea/af/72eaaf5c70436356bce53862c75c7eeb.jpg", 156 | text: "Nice post", 157 | created: new Date(), 158 | }, 159 | { 160 | id: 2, 161 | username: "username", 162 | userImg: 163 | "https://i.pinimg.com/736x/72/ea/af/72eaaf5c70436356bce53862c75c7eeb.jpg", 164 | text: "Nice post Lorem ipsum, dolor sit amet consectetur adipisicing elit. Exercitationem obcaecati totam officia doloremque est reprehenderit ipsam nam optio quisquam velit mollitia aliquid rem, eos repellat natus aliquam voluptatibus laborum, ratione assumenda earum. Beatae ratione recusandae laboriosam quo! Error quaerat esse tempore voluptatibus, aliquid possimus consequuntur doloremque mollitia dicta! Voluptate iure ut fugiat, animi quibusdam mollitia, necessitatibus laborum magnam facere cupiditate amet culpa aspernatur libero dolore porro expedita quia? Tempora modi perferendis natus impedit architecto, odio vitae! Impedit reiciendis, soluta laudantium non aut aliquid dolor. Omnis dolore eaque reiciendis eveniet, eius, facere eligendi ipsum atque iusto magnam deleniti blanditiis, corporis repudiandae?", 165 | created: new Date(), 166 | }, 167 | ]; 168 | --------------------------------------------------------------------------------