How to draw a custom inclined line on Chartjs

I’m trying some open source graphs library to check which is better.
So I stumbled upon Chart.js.

Is it possible to draw a custom sloped line on the graph?

Something like
custom chartjs line

I tryied putting

    // Start a new Path
    ctx.beginPath();
    ctx.moveTo(300, 0);
    ctx.lineTo(0, 300);

    // Draw the Path
    ctx.stroke();

after the graph initialization, so should be drawn after the graph is initialized.

Watch the snippet.

        var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
        var config = {
            type: 'line',
            data: {
                labels: ["January", "February", "March", "April", "May", "June", "July"],
                datasets: [{
                    label: "My First dataset",
                    data: [
                        10, 5, 2, 10, 4, 1, 10
                    ],
                    fill: false,
                }, {
                    label: "My Second dataset",
                    fill: false,
                    data: [
                        8, 3, 8, 6, 8, 8, 8
                    ],
                }]
            },
            options: {
                responsive: true,
                title:{
                    display:true,
                    text:'Chart.js Line Chart'
                },
                tooltips: {
                    mode: 'index',
                    intersect: false,
                },
                hover: {
                    mode: 'nearest',
                    intersect: true
                },
            }
        };

        window.onload = function() {
            var ctx = document.getElementById("canvas").getContext("2d");
            window.myLine = new Chart(ctx, config);
            
            
            
            // Start a new Path
            ctx.beginPath();
            ctx.moveTo(0, 0);
            ctx.lineTo(600, 150);

            // Draw the Path
            ctx.stroke();
        };
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>


<div id="container" style="width: 75%;">
  <canvas id="canvas"></canvas>
</div>

Look the result and…

Nothing happened. ๐Ÿ™

Clear Button Function Not Triggering in Simple Calculator App

I’m a beginner just starting out with web development, and I’m building a simple calculator app using HTML, CSS, and JavaScript. Iโ€™ve encountered an issue where the “Clear” button in my calculator does not seem to trigger the associated function.

Issue:

The displayAppend function works correctly when the calculator buttons are clicked, but the clear function is not getting triggered when the “C” button is clicked. I have confirmed that the console.log statement inside the clear function is not appearing in the console.

Here are the files Iโ€™m working with:

let disp = document.querySelector("#display");

function displayAppend(a) {
  disp.value += a;
}

function clear() {
  console.log("hi");
  disp.value = "";
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Calculator</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div id="calculator">
    <input id="display" readonly>
    <div id="key-container">
      <button onclick="displayAppend('+')" class="keys orange">+</button>
      <button onclick="displayAppend('7')" class="keys">7</button>
      <button onclick="displayAppend('8')" class="keys">8</button>
      <button onclick="displayAppend('9')" class="keys">9</button>
      <button onclick="displayAppend('-')" class="keys orange">-</button>
      <button onclick="displayAppend('4')" class="keys">4</button>
      <button onclick="displayAppend('5')" class="keys">5</button>
      <button onclick="displayAppend('6')" class="keys">6</button>
      <button onclick="displayAppend('*')" class="keys orange">*</button>
      <button onclick="displayAppend('1')" class="keys">1</button>
      <button onclick="displayAppend('2')" class="keys">2</button>
      <button onclick="displayAppend('3')" class="keys">3</button>
      <button onclick="displayAppend('/')" class="keys orange">/</button>
      <button onclick="displayAppend('0')" class="keys">0</button>
      <button onclick="displayAppend('.')" class="keys">.</button>
      <button onclick="Calculate()" class="keys">=</button>
      <button onclick="clear()" class="keys orange">C</button>
    </div>
  </div>
  <script src="calc.js"></script>
</body>

</html>

Verified that the calc.js file is correctly linked and loaded.
Checked that the clear function is correctly defined in the JavaScript file.
Made sure the onclick attribute in the HTML button is properly set.
I would appreciate any guidance on why the clear function isn’t being called or if there’s something I might have missed.

Transform crypt() from PHP to Node.js

I’m having a problem converting crypt() from PHP to Node.js

I have a database with the reg_users table where I have columns like username and password.

In PHP, it’s very simple to encrypt the password in the login system. I receive the raw password from the post and transform it with crypt into a hash:

$user = isset($dado["username"]) ? $dado["username"] : null; $pass = isset($dado["password"]) ? $dado["password"] : null; $password = crypt($pass, '$6$rounds=20000$xtreamcodes$');

When admin is typed, the following hash appears:

$6$rounds=20000$xtreamcodes$XThC5OwfuS0YwS4ahiifzF14vkGbGsFF1w7ETL4sRRC5sOrAWCjWvQJDromZUQoQuwbAXAFdX3h3Cp3vqulpS0

I want to replicate this in node.js, but I can’t.

I’m stuck for 5 days on solving an issue with node.js

I’m taking the web application course and have been building my own website on the side.
I searched everything for 5 days including trying everything chat GPT suggested, for 5 days.. this is killing me..

Please be so kind to help me.. I’ve attached screenshots. 1) HTML 2) items.js 3) app.js. What I’m trying to achieve is to have items.js grab contents from the posts(.html) save them in an object, and then app.js will turn those into a masonrygrid for the index.html. I confirmed that items.js works. But it seems like either app.js is not getting it from items.js (due to some server-client issue which I don’t fully understand) or somehow app.js is not working properly with other files. When I created the object ‘posts’ (Which is an output of items.js) manually, the whole thing worked without a problem.

There might be multiple issues, as I’ve been fixing codes here and there to test.. so even if you spotted one obvious issue, that might already have been tried so kindly look holistically. Again, the whole thing worked when I created the ‘post’ object manually.

Which part is creating an issue? How can I fix it? Thank you tons..!!

import posts from './items.js';

const container = document.querySelector('.container'); // DOM์—์„œ class = container ์ธ ์ฒซ๋ฒˆ์งธ element ์ €์žฅ, ์ด์ œ ์ด๊ฑธ ์•„๋ž˜์„œ manipulate ํ•  ์˜ˆ์ •
console.log(container);

function generateMasonryGrid(columns, posts) {
    container.innerHTML = ''; // ์‹น ์ง€์šฐ๊ณ  ๋‹ค์‹œ ์“ธ ๊ฒƒ   
    let columnWrappers = {}; // ๋นˆ ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ - ์—ฌ๊ธฐ์— ์ปฌ๋Ÿผ ๋ฐ ํฌ์ŠคํŠธ ์ž„์‹œ๋กœ ๋‹ด์•„์„œ ์ž‘์—…ํ•œ ์ˆ˜ container์— ์ง‘์–ด๋„ฃ์„ ์˜ˆ์ •   

    for (let i = 0; i < columns; i++) {
        columnWrappers[`column${i}`] = [];
    }

    for (let i = 0; i < posts.length; i++) {
        const column = i % columns;
        columnWrappers[`column${column}`].push(posts[i]); // ์ปฌ๋Ÿผ๋ณ„๋กœ ํฌ์ŠคํŠธ ์ง‘์–ด๋„ฃ์Œ
    }

    for (let i = 0; i < columns; i++) {
        let columnPosts = columnWrappers[`column${i}`]; // ์ปฌ๋Ÿผ๋ณ„๋กœ ๋‹ค์‹œ ํฌ์ŠคํŠธ ํ•œ๊ฐœ์”ฉ ๋นผ์™€์„œ columnPosts์— ๋„ฃ์Œ
        let div = document.createElement('div'); // HTML์— ๋“ค์–ด๊ฐˆ div ํƒœ๊ทธ ๋งŒ๋“ค๊ณ  
        div.classList.add('column'); // ๊ทธ div์— class = column ๋„ฃ์–ด์คŒ
    
        columnPosts.forEach(post => {  // ์œ„์— ์„œ ์ปฌ๋Ÿผ๋ณ„๋กœ ํฌ์ŠคํŠธ ๋‹ด๊ณ  ์žˆ๋˜ ๊ฐ๊ฐ์˜ ํฌ์ŠคํŠธ์— ๋Œ€ํ•ด 
            let postDiv = document.createElement('div'); // HTML์— ๋“ค์–ด๊ฐˆ div ํƒœ๊ทธ ๋งŒ๋“ค๊ณ 
            postDiv.classList.add('post'); // ๊ทธ div์— class = post ๋„ฃ์–ด์คŒ
            
            let link = document.createElement('a');  // ํฌ์ŠคํŠธ ํด๋ฆญ ๊ฐ€๋Šฅํ•ด์•ผ ํ•˜๋‹ˆ๊นŒ a ํƒœ๊ทธ ๋งŒ๋“ค์–ด์คŒ
            link.href = post.link; // ๊ฐ ํฌ์ŠคํŠธ ๋‚ด์— ๋งํฌ ๋ถˆ๋Ÿฌ์™€์„œ link.href์— ์ €์žฅ
    
            if (post.image) {
                let image = document.createElement('img'); // HTML์— ๋“ค์–ด๊ฐˆ img ํƒœ๊ทธ ๋งŒ๋“ค์–ด์คŒ
                image.src = post.image; // ๊ทธ img ์—๋‹ค๊ฐ€ ํฌ์ŠคํŠธ์˜ ์ด๋ฏธ์ง€ ์ฃผ์†Œ ๋„ฃ์–ด์ฃผ๊ณ 
                link.appendChild(image); // ์œ„์—์„œ ๋งŒ๋“  link, ์ฆ‰ a ํƒœ๊ทธ ์•ˆ์— ๋‹ค์‹œ ๋„ฃ์–ด์„œ syntax ์™„์„ฑ
            }

            if (post.title) {  // ์ด๋ฏธ์ง€๋ž‘ ๋˜‘๊ฐ™์€ ๋กœ์ง
                let title = document.createElement('p');
                title.classList.add('title');
                title.innerText = post.title;
                link.appendChild(title);
            }

            if (post.description) {  // ์ด๋ฏธ์ง€๋ž‘ ๋˜‘๊ฐ™์€ ๋กœ์ง
                let description = document.createElement('p');
                description.classList.add('description');
                description.innerText = post.description;
                link.appendChild(description);
            }
    
            if (post.image || post.description) {  // ์ด๋ฏธ์ง€๋‚˜ ์„ค๋ช… ๋‘˜ ์ค‘ ํ•˜๋‚˜๋งŒ ์žˆ์œผ๋ฉด ์ž‘๋™
                let hoverDiv = document.createElement('div');
                hoverDiv.classList.add('overlay');
        
                let title = document.createElement('h3'); // title์— ์žˆ๋Š”๊ฑธ h3๋กœ ํ•ด์„œ hover ์ด๋ฏธ์ง€์— ๋„ฃ์–ด์คŒ
                title.innerText = post.title;
        
                hoverDiv.appendChild(title);
        
                postDiv.append(link, hoverDiv);
                div.appendChild(postDiv);
            }
        });
        container.appendChild(div);  // ์ง€๊ธˆ๊นŒ์ง€ ๋งŒ๋“ ๊ฑฐ ํฌ์ŠคํŠธ ํ•˜๋‚˜์”ฉ ์ปจํ…Œ์ด๋„ˆ์— ์ €์žฅ
    }
}

console.log(container);



let previousScreenSize = window.innerWidth;

window.addEventListener('resize', () => {
    imageIndex = 0;
    if(window.innerWidth < 600 && previousScreenSize >= 600){
        generateMasonryGrid(1, posts);
    }else if(window.innerWidth >= 600 && window.innerWidth < 1000 && (previousScreenSize < 600 || previousScreenSize >= 1000)){
        generateMasonryGrid(2, posts);
    }else if(window.innerWidth >= 1000 && window.innerWidth < 1500 && (previousScreenSize < 1000 || previousScreenSize >= 1500)){
        generateMasonryGrid(4, posts);
    }else if(window.innerWidth >= 1500 && previousScreenSize < 1500){
        generateMasonryGrid(5, posts)
    }
    previousScreenSize = window.innerWidth;
})

if(previousScreenSize < 600){
    generateMasonryGrid(1, posts)
}else if(previousScreenSize >= 600 && previousScreenSize < 1000){
    generateMasonryGrid(2, posts)
}else if(previousScreenSize >= 1000 && previousScreenSize < 1500){
    generateMasonryGrid(4, posts)
}else{
    generateMasonryGrid(5, posts)
}
const fs = require('fs');
const path = require('path');
const cheerio = require('cheerio');

// Define the folder paths
const projectsFolderPath = path.join(__dirname, 'project');
const memoFolderPath = path.join(__dirname, 'memo');

// Initialize an empty posts array
const posts = [];

// Function to extract data from an HTML file
function extractDataFromHTML(filePath) {
    const fileContent = fs.readFileSync(filePath, 'utf-8');
    const $ = cheerio.load(fileContent);

    const title = $('h1').first().text().trim();
    const description = $('h2').first().text().trim();
    const image = $('img').first().attr('src');

    return {
        title: title || path.basename(filePath, '.html'),
        description: description || 'No description available',
        image: image ? path.join(path.dirname(filePath), image) : '',
        link: filePath.replace(__dirname, '').replace(/\/g, '/')
    };
}

// Function to scan a folder and process HTML files
function scanFolderAndExtractData(folderPath) {
    const files = fs.readdirSync(folderPath);

    files.forEach(file => {
        const filePath = path.join(folderPath, file);
        if (path.extname(file) === '.html') {
            const data = extractDataFromHTML(filePath);
            posts.push(data);
        }
    });
}

// Scan the folders
scanFolderAndExtractData(projectsFolderPath);
scanFolderAndExtractData(memoFolderPath);

// Output the posts array
console.log(posts);
console.log(`Projects folder path: ${projectsFolderPath}`);
console.log(`Memo folder path: ${memoFolderPath}`);

// module.exports = posts;
export default posts;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Will Kwon</title>

    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Work+Sans:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">

    <!-- Favicon -->
    <link rel="icon" type="image/png" sizes="16x16" href="./assets/images/favicon_io/favicon-32x32.png">
    
    <!-- Link to external CSS file -->
    <link rel="stylesheet" href="./assets/styles-new.css">
</head>

<body>
    <main>
        <include src=".htmlsnippetsheader.html"></include>
        
        <div class="container"></div>

        <include src=".htmlsnippetsfooter.html"></include>
    </main>

    <script src="app.js" type="module"></script>
    <script src="htmlsnippetloader.js"></script>
</body>
</html>

Firebase auth in React not working anymore

I used Firebaseui before for authentication with Google. Two weeks everything was working. However, today i tested again and it broke. I reduced this to a minimal app and no errors are logged.. After some debugging, i get the following in one of the links the authentication redirects me to:

Unable to process request due to missing initial state. This may happen if browser sessionStorage is inaccessible or accidentally cleared. Some specific scenarios are – 1) Using IDP-Initiated SAML SSO. 2) Using signInWithRedirect in a storage-partitioned browser environment.

I checked, double checked the configs and i tried in different browsers and incognito mode. All out of ideas here..

Not sure if related, but in the network logs, i see the init.json request has failed as well. (Request URL:
https://jointly-lp2.firebaseapp.com/__/firebase/init.json
Request Method:
GET
Status Code:
404 Not Found)

import React from 'react';
import { getAuth, signInWithRedirect, getRedirectResult, GoogleAuthProvider } from 'firebase/auth';
import { initializeApp } from "firebase/app";


const App = () => {

  // Import the functions you need from the SDKs you need


// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
  apiKey: "AIzaSyDFfSUPdphWmn_1eVy1XjYSX_xyqoQKGJU",
  authDomain: "jointly-lp2.firebaseapp.com",
  projectId: "jointly-lp2",
  storageBucket: "jointly-lp2.appspot.com",
  messagingSenderId: "523205292015",
  appId: "1:523205292015:web:cdfeb66abb1a91105e501a",
  measurementId: "G-5QXB4F1PH9"
};

  // Initialize Firebase
  const app = initializeApp(firebaseConfig);
  const auth = getAuth();
  const provider = new GoogleAuthProvider();

  // Function to handle Google sign-in
  const handleSignIn = async () => {
    try {
      // Initiate the sign-in process with redirect
      await signInWithRedirect(auth, provider);
    } catch (error) {
      console.error("Error during sign-in:", error);
    }
  };

  // Check for sign-in result after redirect
  React.useEffect(() => {
    const fetchUser = async () => {
      try {
        const result = await getRedirectResult(auth);
        if (result) {
          const credential = GoogleAuthProvider.credentialFromResult(result);
          const token = credential.accessToken;
          const user = result.user;

          // Handle the signed-in user information
          console.log("User:", user);
          console.log("Token:", token);
        }
      } catch (error) {
        console.error("Error fetching redirect result:", error);
      }
    };

    fetchUser();
  }, [auth]);

  return (
    <div className="App">
      <button onClick={handleSignIn}>Sign In with Google</button>
    </div>
  );
};

export default App;

Failed to load resource: the server responded with a status of 401 ()

I’m encountering an issue with OTP (One-Time Password) verification in my ASP.NET Core application. I have implemented a LoginWithOTP endpoint in my AuthController, but the OTP code verification is failing.
Verifying OTP: In the LoginWithOTP endpoint, I use the UserManager.VerifyTwoFactorTokenAsync method to verify the OTP code provided by the user.

The OTP code verification fails with a 401 Unauthorized error, despite the OTP code being correct. The logs indicate that the OTP code is invalid, but the stored and provided OTP codes match.

Failed to load resource: the server responded with a status of 401 ()
axiosConfiguration.js:12
Axios error response data:
Object
errorDetails
:
{succeeded: false, isLockedOut: false, isNotAllowed: false, requiresTwoFactor: false}
message
:
“Sign-in failed. Invalid OTP Code.”
status
:
“Error”
[[Prototype]]
:
Object

OtpVerification.jsx

const handleSubmit = async (e) => {
    e.preventDefault();
    setIsLoading(true);

    const cleanCode = otp.join('');

    try {
        const response = await verifyOTP(username, cleanCode);
        console.log("Received response:", response);

        if (response.success) {
            toast.success(response.message || 'OTP Verified Successfully!');
            onOpenChange(false);
        } else {
            toast.error(response.message || 'OTP Verification Failed. Please try again.');
        }
    } catch (error) {
        console.error('Error during OTP verification:', error);
        toast.error('An error occurred during OTP verification. Please try again.');
    } finally {
        setIsLoading(false);
        setOtp(Array(length).fill(''));
    }
};

AuthContext.jsx

import React, { createContext, useState, useContext } from 'react';
import axios from './axiosConfiguration';
import { toast } from 'react-toastify'; 
const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
    const [isAuthenticated, setIsAuthenticated] = useState(false);
    const [token, setToken] = useState('');
    const [user, setUser] = useState(null);
    const [isLoading, setIsLoading] = useState(false);

    const login = (token, user) => {
        sessionStorage.setItem('jwtToken', token);
        sessionStorage.setItem('user', JSON.stringify(user));
        setIsAuthenticated(true);
        setToken(token);
        setUser(user);
    };

    const logout = () => {
        sessionStorage.removeItem('jwtToken');
        sessionStorage.removeItem('user');
        setIsAuthenticated(false);
        setToken('');
        setUser(null);
    };

    async function verifyOTP(username, code) {
        try {
            const response = await axios.post('/api/Auth/loginWithOTP', { username, code });
            if (response.data.Status === 'Success') {
                login(response.data.token, response.data.user);
                toast.success('OTP verified successfully!');
                return { success: true, token: response.data.token, user: response.data.user };
            } else {
                return { success: false, message: response.data.Message };
            }
        } catch (error) {
            console.error('Error verifying OTP:', error);
            return { success: false, message: 'An error occurred. Please try again.' };
        } finally {
            setIsLoading(false);
        }
    }

    return (
        <AuthContext.Provider value={{ isAuthenticated, token, user, login, logout, verifyOTP, setIsLoading, isLoading }}>
            {children}
        </AuthContext.Provider>
    );
};


export const useAuth = () => {
    const context = useContext(AuthContext);
    if (context === undefined) {
        throw new Error('useAuth must be used within an AuthProvider');
    }
    return context;
};

AuthController.cs

[HttpPost]
[Route("loginWithOTP")]
public async Task<IActionResult> LoginWithOTP([FromBody] OtpRequest request)
{
    // Validate request
    if (request == null || string.IsNullOrEmpty(request.Code) || string.IsNullOrEmpty(request.Username))
    {
        _logger.LogWarning("Invalid OTP request: Missing code or username.");
        return BadRequest(new { message = "Code and Username are required" });
    }

    // Find the user
    var user = await _userManager.FindByNameAsync(request.Username);
    if (user == null)
    {
        _logger.LogWarning("OTP verification failed: User not found. Username: {Username}", request.Username);
        return NotFound(new { Status = "Error", Message = "User not found." });
    }

    // Verify OTP
    var validTwoFactorToken = await _userManager.VerifyTwoFactorTokenAsync(user, "Email", request.Code);
    if (!validTwoFactorToken)
    {
        _logger.LogWarning("Invalid OTP code for user: {Username}. Code: {Code}", request.Username,    request.Code);
        return Unauthorized(new { Status = "Error", Message = "Invalid OTP code." });
    }

    // Attempt sign-in
    var signInResult = await _signInManager.TwoFactorSignInAsync(
        "Email",
        request.Code,
        rememberClient: false,
        isPersistent: false);
    _logger.LogInformation("Received OTP code: {Code} for user: {Username}", request.Code, request.Username);


    if (!signInResult.Succeeded)
    {
        string errorMessage = "Sign-in failed. ";

        if (signInResult.IsNotAllowed)
        {
            errorMessage += "User is not allowed to sign in. ";
        }

        if (signInResult.RequiresTwoFactor)
        {
            errorMessage += "User requires two-factor authentication. ";
        }

        if (signInResult.IsLockedOut)
        {
            errorMessage += "User is locked out. ";
        }

        if (signInResult.IsLockedOut || signInResult.IsNotAllowed || signInResult.RequiresTwoFactor)
        {
            // Log these specific scenarios with additional context if needed.
            _logger.LogWarning("Failed OTP verification for user: {Username}. Details: {Details}", request.Username, errorMessage);
        }
        else
        {
            errorMessage += "Invalid OTP Code.";
            _logger.LogWarning("Failed OTP verification for user: {Username}. Reason: Invalid OTP Code.", request);
        }

        return Unauthorized(new { Status = "Error", Message = errorMessage, ErrorDetails = signInResult });
    }

Background Image Not Displaying on Smaller Screens with Tailwind CSS

Iโ€™m having trouble with a background image not displaying correctly on smaller screens in a Tailwind CSS-based project. The image is correctly showing up on larger screens, but it’s not visible or covering the container as expected on smaller devices.

** HTML HERO SECTION**

  <!-- hero -->
      <section
        class="hero min-h-[640px] xl:min-h-[840px] bg-hero bg-center lg:bg-cover bg-no-repeat bg-fixed xl:rounded-bl-[290px] relative z-20" id="Home"
      >
        <div class="container mx-auto">
          <!-- text -->
          <div
            class="hero__text md:w-[567px] flex flex-col items-center text-center xl:text-left lg:items-start"
          >
          <div>
            <h1 class="h1 custom-gradient mb-8 break-words">
              Instant Cash Offer for Your Home
            </h1>
            <p class="mb-8 text-first-onPrimary">
              Sell Fast, No Fees or Commissions. We Buy in Any Condition!
            </p>
          </div>
            <form
              action="/submit"
              method="POST"
              class="flex flex-col lg:flex-row gap-4 min-w-[200px]"
            >
              <!-- Property Address Input -->
              <div class="mb-8 mx-auto xl:mx-0 inline-flex items-center">
                <div class="relative">
                  <label for="property-address" class="sr-only"
                    >Enter Property Address</label
                  >
                  <i
                    class="ri-home-line absolute left-2 top-1/2 transform -translate-y-1/2 text-gray-400"
                  ></i>
                  <input
                    type="text"
                    id="property-address"
                    name="property_address"
                    placeholder="Enter Property Address"
                    class="btn btn-secondary ring-1 ring-gray-200 outline-none focus:ring-8 focus:ring-first-onPrimary focus:text-second-secondary"
                    onfocus="this.previousElementSibling.style.display='none';"
                    onblur="if(this.value===''){this.previousElementSibling.style.display='block';}"
                  />
                </div>
              </div>

              <!-- Phone Input -->
              <div class="mb-8 mx-auto xl:mx-0 inline-flex items-center">
                <div class="relative">
                  <label for="phone" class="sr-only">Phone</label>
                  <i
                    class="ri-smartphone-line absolute left-2 top-1/2 transform -translate-y-1/2 text-gray-400"
                  ></i>
                  <input
                    type="text"
                    id="phone"
                    name="phone"
                    placeholder="Phone"
                    class="btn btn-secondary ring-gray-200 outline-none focus:ring-8 focus:ring-first-onPrimary focus:text-second-secondary"
                    onfocus="this.previousElementSibling.style.display='none';"
                    onblur="if(this.value===''){this.previousElementSibling.style.display='block';}"
                  />
                </div>
              </div>

              <!-- Submit Button -->
              <button
                type="submit"
                class="btn btn-primary inline-flex mx-auto xl:mx-0 items-center"
              >
                GET FREE OFFER
                <i class="ri-arrow-right-line text-first-onPrimary"></i>
              </button>
            </form>
          </div>
        </div>
      </section>

Tailwind Configuration(tailwind.config.js)

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['*.{html,js}', './index.html'],
  theme: {
    container: {
      padding: {
        DEFAULT: '15px',
      },
    },
    screens: {
      sm: '640px',
      md: '768px',
      lg: '960px',
      xl: '1200px',
    },
    fontFamily: {
      primary: 'DM Serif Display',
      secondary: 'Jost',
    },
    backgroundImage: {
      hero: 'url(/assets/hero/Background.png)',
    },
    extend: {
      colors: {
        first: {
          primary: '#40B750',
          primaryLight: 'rgba(249, 238, 216, 0.3)',
          onPrimary: '#EFD59E',
          primaryContainer: '#85D08F',
          onPrimaryContainer: '#F9EED8',
          customGradient:
            'linear-gradient(to right, #85D08F 17%, #85D08F 31%, #EFD59E 46%)',
          hover: '#E0E0E0',
        },
        second: {
          secondary: '#0E0E0E',
          onSecondary: '#FEFEFE',
          secondaryContainer: '#CDE1CF',
          onSecondaryContainer: '#D9D9D9',
        },
        accent: {
          default: '#FF5733', // Default accent color
          secondary: '#33CFFF', // Secondary accent color
          hover: '#E0E0E0',
        },
      },
    },
  },
  plugins: [],
};

**Issue:
**

  • On Desktop: The background image appears correctly and covers the section as expected.

  • On Smaller Screens: The image is not visible on smaller screen devices from the user persepctive, but upon testing if its visible in different browsers in development, it appears.

**Steps I Have Attempted:
**

  1. Verified Image Path:
  • Confirmed that the image path in the bg-hero class is correct and the image is accessible.
  1. Checked Tailwind CSS Output:
  • Verified that the .bg-hero class is correctly defined in the output CSS file generated by Tailwind.
  1. Tested CSS Classes:
  • Removed lg:bg-cover to see if it affects the background image.
  • Applied bg-cover directly to see if it resolves the issue on all screen sizes.
  1. Reviewed Responsive Design:
  • Ensured that Tailwind’s responsive classes are correctly applied and not conflicting.

  • Checked for any media queries in custom CSS that might be overriding Tailwind classes.

  1. Used Developer Tools:
  • Inspected the element with the .hero class in browser developer tools to confirm which styles are applied and if any are missing or overridden.

**Questions:
**

  • How can I ensure to have the picture appear on the user mobile device?

  • Are there any other common issues or pitfalls with Tailwind CSS background images that I might be missing?

Issue with Reinitializing Cropper After Adding Image with Dropzone

Dropzone.autoDiscover = false;
var cropper;

    $(document).ready(function() {

   $('#cropperModal').on('shown.bs.modal', function() {
    console.log('---shown.bs.modal-----');
    //var $image = $('#modalImage');
    let imageElm = document.getElementById('modalImage');
    let section = $('#modalImage').data('section');
    $(imageElm).show();
    console.log(section);
    let aspectRatio = getAspectRatio(section);
    console.log('---shown.bs.modal---- aspectRatio: ' & aspectRatio);
    cropper = new Cropper(imageElm, {
     viewMode: 2,
     responsive: true,
     ready: function() {
      let cropBoxData = cropper.getCropBoxData();
      console.log(cropBoxData);
      let naturalWidth = imageElm.naturalWidth;
      let naturalHeight = imageElm.naturalHeight;
      console.log('naturalWidth ' & naturalWidth);
      cropBoxData.width = naturalWidth;
      cropBoxData.height = naturalHeight;
      cropper.setCropBoxData(cropBoxData);
   },
  crop: function(event) {
    /*console.log(event.detail.x);
    console.log(event.detail.y);
    console.log(event.detail.width);
    console.log(event.detail.height);*/
    }
  });
  }).on('hidden.bs.modal', function() {
    // Destroy the cropper instance when the modal is hidden
    if (cropper) {
      cropper.destroy();
      cropper = null;
    }
  });

$('#upload-header, #upload-horizontal, #upload-logo').on('click', function() {
    let section = $(this).data('section');
    let imageUrl = $(this).find('img').attr('src');
    openModalAndInitializeDropzone(section, imageUrl);
  });


  $('#cropperModal').on('hidden.bs.modal', function() {
    console.log('hidden.bs.modal');
    resetDropzone("#hidden-dropzone");
    $('#modalImage').attr('src', '').hide();
    $('#upload-button').hide();
  });

  $('#save-changes-button').on('click', function() {
    console.log('save changes button clicked');
    saveCroppedImage(cropper);
  });

  function getAspectRatio(section) {
    console.log('getAspectRatio ' + section);
    switch (section) {
      case 'header':
        return 16 / 9;
      case 'horizontal':
        return 4 / 3;
      case 'logo':
        return 1 / 1;
      default:
        return 1 / 1;
    }
  }


  function openModalAndInitializeDropzone(section, imageUrl) {
    $('#cropperModal').modal('show');
    $('#modalImage').attr('src', imageUrl).data('section', section).show();

    initializeDropzone("#hidden-dropzone", getAspectRatio(section),
      function(cropperInstance) {
        cropper = cropperInstance;
      });
  }

  function initializeDropzone(dropzoneId, aspectRatio, cropCallback) {
    console.log('initializeDropzone called');
    if (Dropzone.instances.length > 0) {
      Dropzone.instances.forEach(instance => instance.destroy());
     if (cropper) {
        cropper.destroy();
        cropper = null;
     }
    }
   
    let dropzone = new Dropzone(dropzoneId, {
      url: "/file/post",
      maxFilesize: 2,
      acceptedFiles: ".jpeg,.jpg,.png",
      maxFiles: 1,
      init: function() {
        this.on("addedfile", function(file) {

          console.log('addedfile called');
          var reader = new FileReader();
          reader.onload = function(event) {
            console.log('reader.onload called');
            $('#modalImage').off('load'); // Unbind the previous load event
            $('#modalImage').attr('src', event.target.result).show(); // Load image into modal
            $('#modalImage').on('load', function() {
              //alert('test');
              cropCallback(initializeCropper('#modalImage', aspectRatio));
            });
          };
          reader.readAsDataURL(file);
        });
        this.on("thumbnail", function(file) {
          file.previewElement.remove();
        });
      }
    });
    // Ensure the Dropzone area is visible in the modal
    $(dropzoneId).css({
      display: 'block',
      width: '100%',
      height: '200px',
      border: '2px dashed #007bff',
      padding: '20px',
      textAlign: 'center',
      lineHeight: '160px',
      fontSize: '16px',
      color: '#007bff'
    }).text('Drag and drop an image here or click to upload');
  }

  function resetDropzone(dropzoneId) {
    let dropzoneElement = Dropzone.forElement(dropzoneId);
    if (dropzoneElement) {
      dropzoneElement.removeAllFiles(true);
    }
  }

  function initializeCropper(imageId, aspectRatio) {
    alert('initializeCropper called');
    var $image = $(imageId);
    var section = $image.data('section');
    var aspectRatio = getAspectRatio(section);
    let imageElm = document.getElementById('modalImage');
    console.log(imageElm);
    if ($image.length) {
      if (cropper) {
        cropper.destroy(); // Destroy the previous Cropper instance
        cropper = null;
      }
      
      console.log('Initializing cropper...');
      console.log($image);
      $image.cropper({
         viewMode: 2,
         responsive: true,
        /*aspectRatio: aspectRatio,*/
        crop: function(e) {
          console.log('Crop event:', e);
        },
      ready: function() {
        console.log(cropper);
        let cropBoxData = cropper.getCropBoxData();
        console.log(cropBoxData);
        let naturalWidth = imageElm.naturalWidth;
        let naturalHeight = imageElm.naturalHeight;
        console.log('naturalWidth ' & naturalWidth);
        cropBoxData.width = naturalWidth;
        cropBoxData.height = naturalHeight;
        cropper.setCropBoxData(cropBoxData);
   }
      });
      $('#upload-button').show();
      return $image.data('cropper');
    }

    console.error('Image element not found:', imageId);
    return null;
  }

  function saveCroppedImage(cropper, width, height) {
    if (cropper) {
      var canvas = cropper.getCroppedCanvas({
        width: width,
        height: height
      });

      if (canvas) {
        canvas.toBlob(function(blob) {
          var formData = new FormData();
          formData.append('croppedImage', blob, 'croppedImage.' + blob.type.split('/')[1]);

          $.ajax('/main/uploadFile', {
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function(response) {
              $('#status-gyph-image').html('<strong>Successfully uploaded images.</strong>').addClass('text-success').removeClass('text-danger');
              console.log('Upload success:', response);
            },
            error: function(xhr, status, error) {
              $('#status-gyph-image').html('An internal error occurred.').addClass('text-danger').removeClass('text-success');
              console.error('Upload error:', error, xhr);
            }
          });
        });
      } else {
        $('#status-gyph-image').html('An internal error occurred.').addClass('text-danger').removeClass('text-success');
        console.error('Canvas is null. Cropper might not be properly initialized.');
      }
    } else {
      $('#status-gyph-image').html('An internal error occurred.').addClass('text-danger').removeClass('text-success');
      console.error('Cropper instance is not initialized.');
       }
      }
    });
  • I click โ€œDrag and drop an image here or click to upload,โ€ then select my image file.
    The image is successfully added, and Cropper initializes correctly.
  • I click โ€œDrag and drop an image here or click to uploadโ€ again, select another image file, but this time Cropper does not initialize. the image appears, but there is no Cropper.. I am expecting this to work the 2nd time and beyond that I add an image, not just the first time.

Function Gets Client’s IpAddress

I have A function That Gets My IpAddress when i Try To upload this Function to a server it gets the server IpAddress Not The Client That Makes the action on the Server .
i tried to search to make it either Client Side or Server Side But No Result
your text

That’s The Function :

 public string getIp()
 {   string hostName = Dns.GetHostName();
     Console.WriteLine(hostName);
     string myIP = Dns.GetHostByName(hostName).AddressList[0].ToString();
     string IpAndName = hostName + ":" + myIP;
     return IpAndName;
 }

ChatGPT form with JavaScript

I’m creating a form with ChatGPT API.
So far I can forward a single text via prompt.
How do I forward the text described by the user + selected file in the input label at the same prompt?
When selecting the option, an excel file + question will be inserted.
The question asked at the prompt will be for a conclusion regarding the reading of the selected file.

HTML:

<div class="clients-inputs">
                  <div class="client-title">
                    <h6>Selecione o cliente:</h6>
                  </div>
                  <div class="client-group">
                    <div class="client-input">
                      <input type="radio" id="#####" name="client">
                      <label for="#####">#####</label>
                    </div>
                    <div class="client-input">
                      <input type="radio" id="#####" name="client">
                      <label for="#####">#####</label>
                    </div>
                    <div class="client-input">
                      <input type="radio" id="#####" name="client">
                      <label for="#####">#####</label>
                    </div>
                    <div class="client-input">
                      <input type="radio" id="#####" name="client">
                      <label for="#####">#####</label>
                    </div>
                  </div>
                </div>

JavaScript:

function sendMessage() {
    
    var message = document.getElementById('pergunta')

    if(!message.value){
        message.style.border = '1px solid red'
        return
    }
    message.style.border = 'none'
    
    var status = document.getElementById('status')
    var btnSubmit = document.getElementById('btn-submit')
    var clientInput = document.getElementById('client-input')


    status.style.display = 'block'
    status.innerHTML = 'Carregando...'
    status.style.color = 'white'
    btnSubmit.disabled = true
    btnSubmit.style.cursor = 'not-allowed'
    message.disabled = true

    fetch("https://api.openai.com/v1/chat/completions", {
        method: 'POST',
        headers: {
            Accept: "application/json",
            "Content-Type": "application/json",
            Authorization: `Bearer ${apiKey}`
        },
        body: JSON.stringify({
            model: "gpt-4o-mini",
            messages: [
                {
                    role: "user",
                    content: message.value
                }
            ],
            max_tokens: 8192,
            temperature: 0.7
        })
    })
    .then((response) => response.json())
    .then((response) => {
        let r = response.choices[0].message.content
        status.style.display = 'none'
        showHistoric(message.value,r)
    })
    .catch((error) => {
        console.error('Erro:', error);
    })
    .finally(() => {
        btnSubmit.disabled = false
        btnSubmit.style.cursor = 'pointer'
        message.disabled = false
        message.value = ''
    })
}

Illustration image of the interface.
enter image description here

As I am new to the language, several attempts were made to implement the function, but in none of them I was successful.

Why aren’t SSE messages automatically rendering in my app’s live feed?

I’m building a CRM application that uses Server-Sent Events to receive real-time updates for new messages (pretty simplistic chat UI). While the messages update when I click on a user in the conversation list, the frontend doesn’t automatically update when new data comes in through the webhook. Here’s the relevant code:

import { useEffect } from 'react';
import { getToken } from './auth';

class SSEManager {
  constructor() {
    this.eventSource = null;
    this.listeners = {};
  }

  connect() {
    if (!this.eventSource) {
      this.eventSource = new EventSource('/api/sms/sse');
      this.eventSource.onmessage = this.handleMessage.bind(this);
      this.eventSource.onerror = this.handleError.bind(this);
    }
  }

  handleMessage(event) {
    try {
      const data = JSON.parse(event.data);
      if (this.listeners[data.type]) {
        this.listeners[data.type].forEach(callback => callback(data));
      }
    } catch (error) {
      console.error('Error processing SSE message:', error);
    }
  }


const sseManager = new SSEManager();

export const useSSE = (eventType, callback) => {
  useEffect(() => {
    sseManager.connect();
    sseManager.addEventListener(eventType, callback);

    return () => {
      sseManager.removeEventListener(eventType, callback);
      if (Object.keys(sseManager.listeners).length === 0) {
        sseManager.disconnect();
      }
    };
  }, [eventType, callback]);
};

export const fetchContactMessages = async (contactId) => {
  try {
    const token = getToken();
    const response = await fetch(`/api/contacts/${contactId}?includeMessages=true`, {
      headers: {
        Authorization: `Bearer ${token}`
      }
    });
    if (!response.ok) {
      throw new Error('Failed to fetch contact and messages');
    }
    return await response.json();
  } catch (error) {
    console.error('Error fetching contact and messages:', error);
    throw error;
  }
};

In my component, I’m using the useSSE hook like this:

useSSE('newMessage', async (data) => {
  if (contact && data.contactId === contact._id) {
    await fetchContactMessagesData();
  }
});

The fetchContactMessagesData function is defined as:

const fetchContactMessagesData = useCallback(async () => {
  if (!contact) return;

  setLoading(true);
  setError('');
  try {
    const data = await fetchContactMessages(contact._id);
    if (data.messages && Array.isArray(data.messages)) {
      setMessages(data.messages);
      messagesCache.current[contact._id] = data.messages;
    } else {
      setMessages([]);
      messagesCache.current[contact._id] = [];
    }
    if (data.firstName !== contact.firstName || data.lastName !== contact.lastName) {
      onUpdateContact({...contact, ...data});
    }
    return data;
  } catch (error) {
    console.error('Error fetching contact and messages:', error);
    setError('Failed to fetch messages. Please try again later.');
    toast.error('Failed to fetch messages');
    throw error;
  } finally {
    setLoading(false);
  }
}, [contact, onUpdateContact]);

I am relatively new to web development and this is the first time I am making an app that utilizes SSE. My main 2 questions would be Am I setting up the SSE connection correctly and is there an issue with how I’m handling the new message event in the component? Pretty lost here so any help would be greatly appreciated!

I believe I have already set up the backend properly, I did some logging and it seems like the SSE is properly emitting to the client-side. The SSE connection on the network tab in dev tools says its 200. I am not 100% sure if the data is being sent over to the frontend successfully, the EventStream tab is empty but I have also read that it may be a bug on googles part.

How to append a symbol to user input and allow backspace once appended (to ignore it)

I have a field where the user can enter a number, and I’m trying to append a % symbol to it as the user types.

I’ve done it, but as soon as it appears, the user can no longer use the backspace key, as they’re now technically trying to remove the % symbol.

Is there a way to have the % symbol be ignored, so that the user can backspace through it?

Here is what I’ve done:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Goal Margin Input Example</title>
</head>
<body>
    <label for="goal-margin">Know your goal profit margin?</label>
    <input type="text" id="goal-margin" placeholder="Goal margin">

    <script>
        const goalMarginInput = document.getElementById('goal-margin');

        function handleGoalMarginInput(event) {
            const input = event.target;
            let value = input.value.replace('%', '');  // Remove existing % symbol

            if (!isNaN(value) && value.trim() !== '') {
                value += '%';  // Append % symbol
            }

            input.value = value;
        }

        goalMarginInput.addEventListener('input', handleGoalMarginInput);
    </script>
</body>
</html>

You’ll be able to see what I mean – its a poor user experience to not be able to backspace if you’ve typed the wrong number.

Thanks!

Notice: PHP Request Startup: file created in the system’s temporary directory in Unknown on line 0

I am using dropzone library to upload image in directory in Laravel 10 version. The dropzone java script below and server side code is working fine. From server response they are giving me result in json form, which is fine. But the problem is json is not working in case of success function due to notice in the result.

Error JSON response

Javascript:

Dropzone.autoDiscover = false;
const dropzone = $("#image").dropzone({
init: function(){
this.on('addedfile', function(file){
if(this.files.length > 1){
this.removeFile(this.files[0]);
}
});
},

`url: "{{ route('temp-images.create') }}",`
`maxFiles: 1,`
`paramName: "image",`
`addRemoveLinks: true,`
`acceptedFiles: "image/jpeg,image/png,image/gif",`
`headers: {`
    `'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')`
`}, success: function(file, response){`

    `$("#image_id").val(response.image_id);`
`}`

`});`

Server Side:

`public function create(Request $request){`
    
    `$image = $request->image;`

    `if(!empty($image)) {`
        `$ext = $image->getClientOriginalExtension();`
        `$newName = time().'.'. $ext;`
        
        `$tempImage = new TempImage();`
        `$tempImage->name = $newName;`
        `$tempImage->save();`
        
        `$image->move(public_path(). '/tmp', $newName);`

        `return response()->json([`
            `'status' => true,`
            `'image_id' => $tempImage->id,`
            `'message' => 'Image uploaded successfully.'`
        `]);`

    `}`
`}`

I want only json response not the PHP notice because with that my json is not working. Thanks

I need simple json like:

success JSON response

How to prevent the right and bottom edges of my grid from being white on certain grid sizes?

I have an etch-a-sketch program which works fine apart from one small issue. When I click the “change grid size” button and enter certain numbers (such as 51, 44, 45), the right and bottom edges of my grid are white instead of black. Some numbers like 10, 16, 25, don’t give this issue.

This issue happens in chrome browser. When I use firefox browser, my grid becomes even worse and goes all wonky with a column outside of the grid.

  • I tried resizing the grid itself
  • I tried rounding (up or down) gridSize / gridDimensions to various different values
  • I tried removing the borders of each square
  • I changed border on .squares to outline, just causes the issue on different numbers instead (such as 88)

Here is my code:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="./style.css">
    <script src="main.js" defer></script>
    <title>Etch-a-sketch</title>
  </head>
  <body>
    <button onclick="changeGridSize()">Change grid size...</button>
    <div class="container-border">
      <div class="container"></div>
    </div>
  </body>
</html>
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  background-color: rgb(90, 101, 110);
  display: flex;
  flex-direction: column;
  gap: 50px;
  justify-content: center;
  align-items: center;
}

.container-border {
  border: 1px solid black;
}

.container {
  height: 800px;
  width: 800px;
  background-color: white;
  display: flex;
  flex-wrap: wrap;
}

.squares {
  border: 1px solid black;
}

button {
  font-size: 26px;
  padding: 10px 20px;
  border-radius: 5px;
}

button:hover {
  transition: 0.2s;
  background-color: orange;
  cursor: pointer;
}
let container = document.querySelector(".container");

createGrid(16);

function createGrid(gridDimensions) {  
  let gridSize = 800;
  let gridPixelSize = gridSize / gridDimensions;

  for(row = 1; row < (gridDimensions + 1); row++) {
    let column = 1;
    let square = document.createElement("div");
    square.id = "square-" + row + "-" + column;
    square.className = "squares";
    square.style.height = `${gridPixelSize}px`;
    square.style.width = `${gridPixelSize}px`;
    container.appendChild(square);
    for(column = 2; column < (gridDimensions + 1); column++) {
      let square = document.createElement("div");
      square.id = "square-" + row + "-" + column;
      square.className = "squares";
      square.style.height = `${gridPixelSize}px`;
      square.style.width = `${gridPixelSize}px`;
      container.appendChild(square);
    }
  }
  drawOnGrid(gridPixelSize);
}

function drawOnGrid(gridPixelSize) {
  
  let squares = document.querySelectorAll(".squares");

  squares.forEach((square) => {
    let squareDark = document.createElement("div");
    squareDark.style.height = `${gridPixelSize}px`;
    squareDark.style.width = `${gridPixelSize}px`;
    squareDark.style.backgroundColor = "black";
    let squareDarkOpacity = 0;
    squareDark.style.opacity = `${squareDarkOpacity}`;
    square.appendChild(squareDark);

    square.addEventListener("mouseover", (e) => {
      if(!hasColorBeenSet.includes(square)) {
        hasColorBeenSet.push(square);
        let randomColor = Math.floor(Math.random() * 16777215).toString(16);
        square.style.backgroundColor = `#${randomColor}`;
      }

      squareDarkOpacity += 0.1;
      squareDark.style.opacity = `${squareDarkOpacity}`;
    });
  });
  let hasColorBeenSet = [];
}

function changeGridSize() {
  let validAnswer = false;
  while(!validAnswer) {
    let userInput = prompt("How big should the grid be? Enter a number between 8 to 100.");
    userInput = Number(userInput);
    userInput = Math.round(userInput);

    if(userInput >= 8 && userInput <= 100) {
      validAnswer = true;
      container.innerHTML = "";
      createGrid(userInput);
    }
  }
}

Hide section of form by fieldset id in pmpro based on membership level

I gave a code here but its not working I am using elemetor page builder

function show_tax_excemption_upload(){
if (function_exists(‘pmpro_hasMembershipLevel’) && pmpro_hasMembershipLevel(‘Tax Exempt Organizations’)){
document.getElementById(‘pmpro_form_fieldset-tax-exemption-documents’).style.display = ‘inline’;
}
else
{
document.getElementById(‘pmpro_form_fieldset-tax-exemption-documents’).style.display = ‘none’;
}
}

I tried placing it using code snippet, It should be showing/hide the form element block depend on user membership level