diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2bd1d41 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,23 @@ +## Description +Please provide a brief summary of the changes made in this pull request. Include any relevant context or background information. + +## Related Issue +Link to the issue this PR addresses (if applicable): +- Fixes #[issue number] + +## Type of Change +- [ ] Bug fix +- [ ] New feature +- [ ] Documentation update +- [ ] Other (please describe): + +## Checklist +- [ ] I have read the contributing guidelines. +- [ ] I have followed the code style of this project. +- [ ] My code implements the changes requested in the issue. +- [ ] I have added tests to cover my changes (if applicable). +- [ ] I have updated the documentation (if necessary). +- [ ] This PR is ready for review. + +## Additional Notes +Any other information that reviewers should know about this PR. diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..f9eb1d9 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,92 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '24 10 * * 6' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: javascript-typescript + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # โ„น๏ธ Command-line programs to run using the OS shell. + # ๐Ÿ“š See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/discord-notification.yml b/.github/workflows/discord-notification.yml new file mode 100644 index 0000000..c8e0f69 --- /dev/null +++ b/.github/workflows/discord-notification.yml @@ -0,0 +1,64 @@ +name: Discord Notifications + +on: + issues: + types: [opened, closed, reopened] + pull_request: + types: [opened, closed, reopened, merged] + push: + branches: + - main # You can specify other branches as well + +jobs: + notify: + runs-on: ubuntu-latest + steps: + - name: Send Discord Notification + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} # Set your webhook URL in repo secrets + run: | + DISCORD_MESSAGE="๐Ÿ”” **GitHub Event Notification** ๐Ÿ””\n" + DISCORD_MESSAGE+="---------------------------------------------\n" + DISCORD_MESSAGE+="**Event Type**: ${GITHUB_EVENT_NAME}\n" + DISCORD_MESSAGE+="**Repository**: [${GITHUB_REPOSITORY}](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY})\n" + DISCORD_MESSAGE+="**Triggered by**: ${GITHUB_ACTOR}\n" + DISCORD_MESSAGE+="**Timestamp**: $(date)\n" + DISCORD_MESSAGE+="---------------------------------------------\n" + + # Handle pull request events + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + PR_TITLE=$(jq -r '.pull_request.title' "${GITHUB_EVENT_PATH}") + PR_NUMBER=$(jq -r '.pull_request.number' "${GITHUB_EVENT_PATH}") + PR_URL=$(jq -r '.pull_request.html_url' "${GITHUB_EVENT_PATH}") + PR_BRANCH=$(jq -r '.pull_request.head.ref' "${GITHUB_EVENT_PATH}") + PR_ACTION=$(jq -r '.action' "${GITHUB_EVENT_PATH}") + DISCORD_MESSAGE+="๐Ÿš€ **Pull Request** [#${PR_NUMBER} - ${PR_TITLE}](${PR_URL})\n" + DISCORD_MESSAGE+="**Action**: ${PR_ACTION}\n" + DISCORD_MESSAGE+="**Branch**: ${PR_BRANCH}\n" + fi + + # Handle issue events + if [[ "${{ github.event_name }}" == "issues" ]]; then + ISSUE_TITLE=$(jq -r '.issue.title' "${GITHUB_EVENT_PATH}") + ISSUE_NUMBER=$(jq -r '.issue.number' "${GITHUB_EVENT_PATH}") + ISSUE_URL=$(jq -r '.issue.html_url' "${GITHUB_EVENT_PATH}") + ISSUE_ACTION=$(jq -r '.action' "${GITHUB_EVENT_PATH}") + DISCORD_MESSAGE+="๐Ÿ“„ **Issue** [#${ISSUE_NUMBER} - ${ISSUE_TITLE}](${ISSUE_URL})\n" + DISCORD_MESSAGE+="**Action**: ${ISSUE_ACTION}\n" + fi + + # Handle push events + if [[ "${{ github.event_name }}" == "push" ]]; then + COMMIT_MESSAGE=$(jq -r '.head_commit.message' "${GITHUB_EVENT_PATH}") + COMMIT_URL=$(jq -r '.head_commit.url' "${GITHUB_EVENT_PATH}") + PUSH_BRANCH=$(jq -r '.ref' "${GITHUB_EVENT_PATH}") + DISCORD_MESSAGE+="๐Ÿ› ๏ธ **Push Event**\n" + DISCORD_MESSAGE+="**Branch**: ${PUSH_BRANCH}\n" + DISCORD_MESSAGE+="**Commit Message**: ${COMMIT_MESSAGE}\n" + DISCORD_MESSAGE+="๐Ÿ”— [View Commit](${COMMIT_URL})\n" + fi + + # Send the notification to Discord + curl -H "Content-Type: application/json" \ + -d "{\"content\": \"$DISCORD_MESSAGE\"}" \ + $DISCORD_WEBHOOK_URL diff --git a/README.md b/README.md index a703297..089c8a9 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ 5. [Getting Started](#getting-started) 6. [FAQ](#faq) 7. [Contact](#contact) + 8. [Code of Conduct](#code-of-conduct)
@@ -39,7 +40,7 @@ ##
-

High VoltageTechnologies Used

+

High Voltage Technologies Used

- **Front-end:** HTML, CSS, JavaScript, Bootstrap for a responsive design. @@ -50,7 +51,7 @@
-## :sparkles:Contributing +## โœจContributing We welcome contributions from the open-source community! If you'd like to contribute: @@ -59,6 +60,12 @@ We welcome contributions from the open-source community! If you'd like to contri 3. Commit your changes *(git commit -m 'Add some feature').* 4. Push to the branch *(git push origin feature/your-feature).* 5. Open a Pull Request. + +To maintain quality and consistency, please adhere to the following guidelines: +1. Code Style: Follow the coding style used throughout the project. Clean, readable code with comments is always appreciated. +2. Commits: Write meaningful commit messages. +3. Pull Requests: Make sure PRs are focused, well-explained, and reference any issues they address. +4. Testing: Ensure that your changes are well-tested locally and donโ€™t break existing functionality.
@@ -167,7 +174,9 @@ For Queries and issue related question you can contact me on Discord *Discord Username:* akshaypatell_ +## ๐Ÿช„Code of conduct +Want to be part of the community? Check out our **[Code of Conduct](https://github.com/VesperAkshay/qr-code-generator/blob/main/Code_Of_Conduct.md)**
diff --git a/package-lock.json b/package-lock.json index 69894f6..cfe3668 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "react": "^18.3.1", "react-color": "^2.19.3", "react-dom": "^18.3.1", + "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", "react-qr-code": "^2.0.15", "react-router-dom": "^6.26.0", @@ -9812,6 +9813,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz", + "integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -15992,6 +16001,21 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-hot-toast": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz", + "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-icons": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", diff --git a/package.json b/package.json index 33816d6..7a61535 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "react": "^18.3.1", "react-color": "^2.19.3", "react-dom": "^18.3.1", + "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", "react-qr-code": "^2.0.15", "react-router-dom": "^6.26.0", diff --git a/src/App.js b/src/App.js index d56fd12..c10c0d3 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; import Navbar from "./components/Navbar"; import Home from "./pages/Home"; @@ -16,6 +16,8 @@ import BulkQRCode from "./components/BulkQRCode"; import QRScanner from "./components/QRScanner"; import PdfQRCodeGenerator from "./components/PDFToQR"; import { ThemeProvider } from "./context/ThemeContext"; +import { Toaster } from "react-hot-toast"; + export default function App() { return ( @@ -39,6 +41,7 @@ export default function App() { } />
+ diff --git a/src/components/CategorySelector.js b/src/components/CategorySelector.js index 04fdec7..50a54b0 100644 --- a/src/components/CategorySelector.js +++ b/src/components/CategorySelector.js @@ -35,13 +35,13 @@ export default function CategorySelector({ category, handleCategoryChange }) { }} > diff --git a/src/components/ColorPicker.js b/src/components/ColorPicker.js index 4a50c73..9b099d1 100644 --- a/src/components/ColorPicker.js +++ b/src/components/ColorPicker.js @@ -7,55 +7,55 @@ export default function ColorPicker({ color, setColor, bgColor, setBgColor, eyeC
-
-
-
-
-
-
+ {/* Mobile Dropdown Menu */} + {dropdownOpen && ( +
+ {currentUser ? ( + <> + + + Dashboard + + + + Profile + + + + Settings + + + + + ) : ( + <> + + + Login + + + + Register + + + )} +
+ )} ); } diff --git a/src/components/Profile.js b/src/components/Profile.js index f107243..365e696 100644 --- a/src/components/Profile.js +++ b/src/components/Profile.js @@ -6,6 +6,7 @@ import { FaUserEdit, FaLock, FaSignOutAlt, FaEdit } from "react-icons/fa"; import { MdMarkEmailRead } from "react-icons/md"; // Make sure the path is correct import { motion } from "framer-motion"; import AvatarSelectionModal from "./AvatarSelectionModel"; +import toast from "react-hot-toast"; const avatars = [ "/avatars/avatar1.png", @@ -38,10 +39,13 @@ export default function Profile() { displayName, photoURL: selectedAvatar, }); - setSuccess("Profile updated successfully!"); + toast.success("Profile updated successfully!"); + // setSuccess("Profile updated successfully!"); setError(""); } catch (error) { - setError(error.message); + toast.error("Cannot update Profile"); + // setError(error.message); + console.error(error.message); setSuccess(""); } }; @@ -50,23 +54,57 @@ export default function Profile() { try { if (newPassword) { await updatePassword(currentUser, newPassword); - setSuccess("Password updated successfully!"); + // setSuccess("Password updated successfully!"); + toast.success("Password updated successfully!"); setError(""); } } catch (error) { - setError(error.message); + toast.error("Cannot update Password"); + // setError(error.message); + console.error(error.message); setSuccess(""); } }; const handleLogout = async () => { - try { - await logout(); - navigate("/"); - } catch (error) { - setError("Failed to log out: " + error.message); - setSuccess(""); - } + // Show a confirmation toast + const confirmation = toast( + (t) => ( +
+

Are you sure you want to log out?

+
+ + +
+
+ ), + { + duration: 0, // Keep the toast open until dismissed + position: 'top-center', // Adjust position if needed + } + ) }; const openModal = () => setIsModalOpen(true); @@ -138,15 +176,14 @@ export default function Profile() { >
- - -
+ +
{ - const qrCodeInstance = new QRCodeStyling({ + // Initialize QRCodeStyling instance once + if (!qrCodeInstance.current) { + qrCodeInstance.current = new QRCodeStyling({ width: size, height: size, - data: text, - dotsOptions: { color, type: shape }, + data: '', + dotsOptions: { color: color, type: shape }, cornersSquareOptions: { type: frame }, cornersDotOptions: { type: eyeShape, color: eyeColor }, backgroundOptions: { color: bgColor }, }); - setQrCode(qrCodeInstance); - }, [text, color, bgColor, size, shape, frame, eyeShape, eyeColor]); + } const handleGenerate = async () => { + + // Check for required fields based on selected category + if (category === 'vCard') { + if (!vCardDetails.fullName || !vCardDetails.organization || !vCardDetails.phone || !vCardDetails.email) { + toast.error("Please fill in all fields for vCard."); + return; + } + setText(`BEGIN:VCARD\nVERSION:3.0\nFN:${vCardDetails.fullName}\nORG:${vCardDetails.organization}\nTEL:${vCardDetails.phone}\nEMAIL:${vCardDetails.email}\nEND:VCARD`); + } else if (category === 'wifi') { + if (!wifiDetails.ssid || !wifiDetails.password) { + toast.error("Please fill in the SSID and password for WiFi."); + return; + } + setText(`WIFI:T:${wifiDetails.encryption};S:${wifiDetails.ssid};P:${wifiDetails.password};;`); + } else if (category === 'text' || category === 'URL') { + if (!text.trim()) { + toast.error("Text field is empty. Please enter valid data."); + return; + } + } else if ( category === 'URL') { + if (!text.trim()) { + toast.error("Please fill in URL field"); + return; + } + } + + setQrGenerated(false); // Reset QR generated state + + // Clear previous QR code if present if (qrCodeRef.current) { - qrCodeRef.current.innerHTML = ''; // Clear the previous QR code + qrCodeRef.current.innerHTML = ''; } - let logoURL = ''; - if (logoFile) { - const reader = new FileReader(); - reader.onload = (event) => { - logoURL = event.target.result; - qrCode.update({ - data: text, - dotsOptions: { color, type: shape }, - cornersSquareOptions: { type: frame }, - cornersDotOptions: { type: eyeShape, color: eyeColor }, - backgroundOptions: { color: bgColor }, - image: logoURL, - }); - qrCode.append(qrCodeRef.current); - }; - reader.readAsDataURL(logoFile); - } else { - qrCode.update({ + // Create a promise to handle logo loading if applicable + const updateQRCode = (logoURL = '') => { + qrCodeInstance.current.update({ data: text, dotsOptions: { color, type: shape }, cornersSquareOptions: { type: frame }, cornersDotOptions: { type: eyeShape, color: eyeColor }, backgroundOptions: { color: bgColor }, + image: logoURL, // Use logo URL if present }); - qrCode.append(qrCodeRef.current); - } - const userRef = doc(db, "users", currentUser.uid); - const docSnap = await getDoc(userRef); + qrCodeInstance.current.append(qrCodeRef.current); - if (docSnap.exists()) { - const userData = docSnap.data(); - if (userData.qrCount >= 10) { - alert("You have reached the daily limit of QR codes."); - } else { - await updateDoc(userRef, { qrCount: userData.qrCount + 1 }); - } + // Delay a bit to ensure it's appended, then update state + setTimeout(() => { + setQrGenerated(true); // Mark QR code as generated + }, 500); // Set delay to ensure QR is rendered + }; + + if (logoFile) { + const reader = new FileReader(); + reader.onload = (event) => { + const logoURL = event.target.result; + updateQRCode(logoURL); + }; + reader.readAsDataURL(logoFile); } else { - await setDoc(userRef, { qrCount: 1 }); + updateQRCode(); // No logo case } }; const handleDownload = () => { - qrCode.download({ name: "qr_code", extension: downloadFormat }); + qrCodeInstance.current.download({ name: "qr_code", extension: downloadFormat }); }; const handleCategoryChange = (category) => { setCategory(category); + setQrGenerated(false); // Reset QR generated state + setText(''); // Clear text input + + // Clear previous QR code if present + if (qrCodeRef.current) { + qrCodeRef.current.innerHTML = ''; + } + if (category === 'vCard') { setText(`BEGIN:VCARD\nVERSION:3.0\nFN:${vCardDetails.fullName}\nORG:${vCardDetails.organization}\nTEL:${vCardDetails.phone}\nEMAIL:${vCardDetails.email}\nEND:VCARD`); } else if (category === 'URL') { - setText('https://example.com'); + setText(''); } else if (category === 'wifi') { setText(`WIFI:T:${wifiDetails.encryption};S:${wifiDetails.ssid};P:${wifiDetails.password};;`); } else if (category === 'text') { @@ -120,11 +143,11 @@ export default function QRCodeGenerator() { return ( - - + {/* QR code will appear only if it's been generated */} +
+ + {/* Only show download options if QR code has been generated */} + {qrGenerated && ( + + )}
); } diff --git a/src/components/QRScanner.js b/src/components/QRScanner.js index cac2ac1..4eb1f03 100644 --- a/src/components/QRScanner.js +++ b/src/components/QRScanner.js @@ -1,6 +1,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { FaClipboard, FaCamera, FaImage, FaTimes, FaCheck, FaLightbulb } from 'react-icons/fa'; import QrScanner from "qr-scanner"; +import toast from 'react-hot-toast'; export default function QRScanner() { const [scannedData, setScannedData] = useState({}); @@ -114,9 +115,10 @@ export default function QRScanner() { const copyToClipboard = () => { navigator.clipboard.writeText(scannedData.result) .then(() => { - alert('Copied to clipboard'); + toast.success('Copied to clipboard'); }) .catch(err => { + toast.error('Failed to copy'); console.error('Failed to copy: ', err); }); }; diff --git a/src/components/Register.js b/src/components/Register.js index 4470027..beed8af 100644 --- a/src/components/Register.js +++ b/src/components/Register.js @@ -4,6 +4,7 @@ import { auth } from '../firebase'; import { useNavigate } from 'react-router-dom'; import { motion } from 'framer-motion'; import { FcGoogle } from 'react-icons/fc'; +import toast from 'react-hot-toast'; export default function Register() { const [email, setEmail] = useState(''); @@ -15,8 +16,10 @@ export default function Register() { try { await createUserWithEmailAndPassword(auth, email, password); navigate('/dashboard'); + toast.success('Registered successfully'); } catch (error) { - alert(error.message); + toast.error('Something went wrong'); + console.error(error.message); } }; @@ -25,8 +28,10 @@ export default function Register() { try { await signInWithPopup(auth, provider); navigate('/dashboard'); + toast.success('Registered successfully'); } catch (error) { - alert(error.message); + toast.error('Something went wrong'); + console.error(error.message); } }; diff --git a/src/components/Setting.js b/src/components/Setting.js index d8b8770..2e5c306 100644 --- a/src/components/Setting.js +++ b/src/components/Setting.js @@ -5,6 +5,7 @@ import { useAuth } from '../context/AuthContext'; import { updateProfile, updateEmail, updatePassword } from 'firebase/auth'; import { useNavigate } from 'react-router-dom'; import { motion } from 'framer-motion'; +import toast from 'react-hot-toast'; export default function Settings() { const { currentUser, logout } = useAuth(); @@ -19,10 +20,11 @@ export default function Settings() { const handleUpdateProfile = async () => { try { await updateProfile(currentUser, { displayName }); - setSuccess('Profile updated successfully!'); + toast.success('Profile updated successfully!'); setError(''); } catch (error) { - setError(error.message); + toast.error('Something went wrong'); + console.error(error.message); setSuccess(''); } }; @@ -32,11 +34,12 @@ export default function Settings() { try { if (email) { await updateEmail(currentUser, email); - setSuccess('Email updated successfully!'); + toast.success('Email updated successfully!'); setError(''); } } catch (error) { - setError(error.message); + toast.error('Something went wrong'); + console.error(error.message); setSuccess(''); } }; @@ -46,24 +49,56 @@ export default function Settings() { try { if (newPassword) { await updatePassword(currentUser, newPassword); - setSuccess('Password updated successfully!'); + toast.success('Password updated successfully!'); setError(''); } } catch (error) { - setError(error.message); + toast.error('Something went wrong'); + console.error(error.message); setSuccess(''); } }; // Function to handle logout const handleLogout = async () => { - try { - await logout(); - navigate('/'); // Redirect to the home page after logout - } catch (error) { - setError('Failed to log out: ' + error.message); - setSuccess(''); - } + // Show a confirmation toast + const confirmation = toast( + (t) => ( +
+

Are you sure you want to log out?

+
+ + +
+
+ ), + { + duration: 0, // Keep the toast open until dismissed + position: 'top-center', // Adjust position if needed + } + ) }; return ( diff --git a/src/components/SizeSlider.js b/src/components/SizeSlider.js index 107891d..f85c486 100644 --- a/src/components/SizeSlider.js +++ b/src/components/SizeSlider.js @@ -4,8 +4,8 @@ import { FaExpandArrowsAlt } from 'react-icons/fa'; export default function SizeSlider({ size, setSize }) { return (
-