Tuesday, 5 August 2025

React useCallback Hook



We'll use useCallback to :

  • Passing a function as prop to React.memo child
  • Prevents unnecessary re-renders
  • Setting up event handlers inside components
  • Prevents recreation of handler functions
  • Functions inside useEffect/useMemo that need stable reference
  • Avoids infinite loops or unnecessary logic execution
Example : 

import React, { useCallback, useState } from 'react';
import './App.css';
import Dashboard from './component/Dashboard';

const Child = React.memo(({ onClick }) => {
  console.log('Child rendered');
  return <button onClick={onClick}>Click Me</button>;
});

function App() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log('Clicked');
  }, []);

  return (
    <div className="App">
      <Dashboard />
      <h2>React useCallback Example</h2>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Child onClick={handleClick} />
    </div>
  );
}

export default App;

React useRef Hook


We'll use useRef to :

  • Automatically focus the input on mount.
  • Allow the user to click a "Focus Input" button to manually refocus.
  • Autofocuses an input on mount
  • Tracks the previous input value
  • Shows how many times the input changed without causing re-renders
Example : 

import { useRef, useEffect, useState } from 'react';

const TodoAppUseRef = () => {
  const inputRef = useRef(null); // Ref for input focus
  const prevInputRef = useRef(''); // Ref for previous input value
  const [tasks, setTasks] = useState([]);
  const [inputValue, setInputValue] = useState('');

  // Auto-focus input on mount
  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  // Update previous input value after each change
  useEffect(() => {
    prevInputRef.current = inputValue;
  }, [inputValue]);

  const handleAddTask = () => {
    if (inputValue.trim()) {
      setTasks([...tasks, inputValue.trim()]);
      setInputValue('');
      inputRef.current?.focus(); // Refocus after adding
    }
  };

  return (
    <div style={{ padding: '2rem', fontFamily: 'Arial', maxWidth: 500 }}>
      <h2>📝 To-Do List</h2>

      {/* Input with ref and value tracking */}
      <input
        ref={inputRef}
        type="text"
        value={inputValue}
        placeholder="Enter a task..."
        onChange={(e) => setInputValue(e.target.value)}
        style={{
          padding: '0.5rem',
          width: '100%',
          marginBottom: '0.5rem',
          fontSize: '1rem',
        }}
      />

      {/* Previous value display */}
      <p style={{ fontSize: '0.9rem', color: 'gray' }}>
        🔙 Previous Input: <strong>{prevInputRef.current}</strong>
      </p>

      {/* Action buttons */}
      <div style={{ display: 'flex', gap: '1rem', marginBottom: '1rem' }}>
        <button onClick={handleAddTask}>Add Task</button>
        <button onClick={() => inputRef.current?.focus()}>🔍 Focus Input</button>
      </div>

      {/* Task list */}
      <ul>
        {tasks.map((task, index) => (
          <li key={index} style={{ padding: '0.3rem 0' }}>
            ✅ {task}
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoAppUseRef;

Sunday, 3 August 2025

Crawl Page And Capture Screenshot PDF


This function does :

  • Full-Page PDF Generation
  • Recursive Internal Link Crawling
  • Content and Metadata Extraction
  • Intelligent Overlay & Popup Handling
  • Auto Scroll to Load Dynamic Content
  • Persistent File & DB Storage
  • User and Context-Aware
  • Timeout and Error Handling

private async crawlPage(
        browser: Browser,
        url: string,
        user: User,
        depth: number,
        visited: Set<string>,
        parent: any,
    ) {
        if (visited.has(url) || depth < 0) return;
        visited.add(url);

        this.logger.log(`🔍 Crawling URL: ${url} (Depth: ${depth})`);

        const existingEntryURL = await this.KnowledgeBaseDetailRepo.findOne({
            where: { url, user: { id: user.id } },
            relations: ['user'],
        });

        const page = await browser.newPage();

        try {
            await page.setUserAgent(
                'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
            );
            await page.setExtraHTTPHeaders({ 'Accept-Language': 'en-US,en;q=0.9' });
            await page.setDefaultNavigationTimeout(60000);
            await page.goto(url, { waitUntil: 'networkidle2' });

            // Reject cookie popups
            const rejectButtonSelectors = [
                '[id*="reject"]', '[id*="deny"]', '[id*="decline"]',
                '[class*="reject"]', '[class*="deny"]', '[class*="decline"]',
                'button:text("Reject")', 'button:text("Deny")', 'button:text("Decline")',
                'button:text("Manage preferences")'
            ];
            for (const selector of rejectButtonSelectors) {
                try {
                    const button = await page.waitForSelector(selector, { timeout: 2000 });
                    if (button) {
                        await button.click();
                        this.logger.log(`✅ Rejected popup on ${url}`);
                        break;
                    }
                } catch { }
            }

            // Scroll entire page to trigger lazy loading
            await page.evaluate(async () => {
                const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
                let totalHeight = 0;
                const distance = 500;
                while (totalHeight < document.body.scrollHeight) {
                    window.scrollBy(0, distance);
                    await delay(500);
                    totalHeight += distance;
                }
            });

            // Remove sticky/fixed overlays
            await page.evaluate(() => {
                const elements = Array.from(document.querySelectorAll('*')) as HTMLElement[];

                // Remove cookie overlays and full-screen modals
                const overlaySelectors = [
                    '[class*="overlay"]', '[id*="overlay"]',
                    '.popup', '.modal', '[class*="cookie"]', '[id*="cookie"]',
                    '[class*="consent"]', '[id*="consent"]'
                ];
                overlaySelectors.forEach(selector => {
                    document.querySelectorAll(selector).forEach(el => el.remove());
                });

                // Ensure sticky headers are visible (don't forcibly un-stick)
                const headers = document.querySelectorAll('header') as NodeListOf<HTMLElement>;
                headers.forEach(header => {
                    header.style.position = 'relative';
                    header.style.top = '0';
                    header.style.left = '0';
                    header.style.width = '100%';
                    header.style.zIndex = '9999';
                    header.style.display = 'block';
                    header.style.visibility = 'visible';
                    header.style.opacity = '1';
                });               
            });

            await page.evaluate(() => window.scrollTo(0, 0));
            await new Promise(res => setTimeout(res, 2000));
                     
            const pdfBuffer: Buffer = Buffer.from(await page.pdf({
                format: 'A4',
                printBackground: true,
                // margin: { top: '20px', bottom: '20px', left: '20px', right: '20px' },
            }));

            // Metadata
            const title = await page.title();
            const content = await page.evaluate(() => document.body?.innerText || '');
            const language = langdetect.detectOne(content.slice(0, 5000)) || 'unknown';
            const safeTitle = (title || 'page').replace(/[^a-zA-Z0-9-_]/g, '_').slice(0, 300);
            const filename = `${safeTitle}.pdf`;
            const folderName = user?.id?.toString();
            const pdfDir = path.resolve(__dirname, '..', '..', 'screenshots', folderName);
            if (!fs.existsSync(pdfDir)) fs.mkdirSync(pdfDir, { recursive: true });
            const pdfPath = path.join(pdfDir, filename);

            // Save PDF and entry
            if (!existingEntryURL) {
                fs.writeFileSync(pdfPath, pdfBuffer);
                this.logger.log(`📄 PDF saved at: ${pdfPath}`);

                await this.KnowledgeBaseDetailRepo.save(
                    this.KnowledgeBaseDetailRepo.create({
                        url,
                        title,
                        content,
                        language,
                        s3path: pdfPath,
                        status: true,
                        uploadDocument: false,
                        user,
                        parent,
                    }),
                );
                this.logger.log(`✅ Saved crawl entry for ${url}`);
            }

            // Recursive crawl internal links
            if (depth > 0) {
                const internalLinks: string[] = await page.evaluate((currentUrl) => {
                    const anchors = Array.from(document.querySelectorAll('a[href]'));
                    return anchors
                        .map(a => a.getAttribute('href'))
                        .filter(Boolean)
                        .map(href => {
                            try {
                                return new URL(href!, currentUrl).href;
                            } catch {
                                return null;
                            }
                        })
                        .filter(href => href && href.startsWith(new URL(currentUrl).origin))
                        .map(href => href!.split('#')[0])
                        .filter((v, i, self) => self.indexOf(v) === i);
                }, url);

                for (const link of internalLinks) {
                    if (!visited.has(link)) {
                        await this.crawlPage(browser, link, user, depth - 1, visited, parent);
                    }
                }
            }

        } catch (error) {
            this.logger.warn(`⚠️ Error crawling ${url}: ${error.message}`);
        } finally {
            await page.close();
        }
    }

Wednesday, 22 January 2025

Git commands


Git commands : 

1. Git configuration :

git config --global user.name "<Your-Full-Name>" // Sets your name for all Git repositories.

git config --global user.email "<your-email-address>" // Sets your email for all Git repositories.

2. Git repository management :

git init // Initializes a new Git repository in the current directory.

git clone <url> // Clones a repository from a remote URL.

3. File status and staging :

git status // Displays the status of the working directory and staging area.

git add . // Stages all changes (new files, modifications, and deletions) for commit.

git commit -m 'message' // Commits the staged changes with a descriptive message.

4. Pushing changes :

git push // Pushes local commits to the remote repository.

5. Branching and switching branches:

git branch <branch-name> // Creates a new branch locally.

git checkout <branch-name> // Switches to an existing branch.

git checkout -b <branch-name> // Creates and switches to a new branch.

git merge <branch-name> // Merges the specified branch into the current branch.

6. Fetching and pulling changes :

git pull // Fetches and merges changes from the remote repository to your local repository.

7. Commit history and differences :

git log // Displays the commit history of the repository.

git diff // Shows the differences between files or commits.

8. Resetting changes :

git reset // Resets changes to the last commit or a specific state (e.g., git reset HEAD <file> to unstage changes).

git reset --hard // Resets the working directory and staging area to the last commit (losing local changes).

9. git stash :

git stash // Saves all uncommitted changes (tracked files only). Resets your working directory to the last committed state.

Tuesday, 21 January 2025

Docker: Accelerated Container Application Development

 

Docker: Accelerated Container Application Development

1. Developers can deploy, run, and manage applications.

2. Deploy applications quickly.

3. Docker is a containerization platform that simplifies the process of deploying and managing applications. Applications run along with their dependencies. 

Docker Images :

1. A copy of our project.

2. Images are made from source code, libraries, and external dependencies.

3. Images are created from source code.

4. Example: Node setup, application code, installed libraries, Docker files.

5. Once an image is created, it cannot be updated; we can create a new image instead.

Docker Container :

1. A container runs applications using images.

2. Containers run independently.

3. Example: If 3 images are available, all these images can run independently.  

Docker Commands :

1. docker build -t folder/dockername . // Creates a project image.

2. docker run -p 5000:5000 -d dockerImageName // Runs a container.

3. docker ps // Shows all running containers.

4. docker logs container_id // Displays project logs.

5. docker image prune // Removes unused images.

6. docker service scale web-app=2 // Scales the web-app service to two replicas.

7. docker service update --image <new-image> service_name // Updates a Docker container's image without causing downtime. 

Docker File Example :

1. Create a file named Dockerfile in the root directory of your backend project.

2. In this Dockerfile, write the following code:

# Use Node.js version 20 as the base image
FROM node:20  

# Set the working directory inside the container
WORKDIR /node-practical  

# Copy package.json and package-lock.json to the working directory
COPY package*.json ./  

# Install dependencies
RUN npm install  

# Copy the entire project to the container
COPY . .  

# Specify the command to run the application
CMD ["node", "index.js"]

3. Here’s an example of a docker-compose.yml file for a microservices architecture:

    docker-compose.yml Example : 

version: '3.9'
services:
  db:
    image: postgres:14-alpine
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: DBPass@123
      POSTGRES_DB: DBNAME
      POSTGRES_HOST_AUTH_METHOD: trust        
     
  gateway:
    build:
      dockerfile: Dockerfile
      context: ./gateway
    command: npm run start:prod
    restart: always  
    ports:
      - "5000:5000"
    depends_on:
      - db      
    environment:
      JWT_SECRET: secret@123
      JWT_EXPIRESIN: 2d
      REDIS_HOST: localhost
      REDIS_PORT: 6379
      REDIS_DB: TestFinAssetMgmt //if use redis
    volumes:          
      - /gateway/src/app/node_modules
 
  auth:
    build:
      dockerfile: Dockerfile
      context: ./auth
    command: npm run start:prod
    restart: always
    ports:
      - "5100:5100"
    depends_on:
      - db      
    environment:
      DB_TYPE : postgres
      DB_HOST : HOST_name
      DB_PORT : 5432
      DB_USERNAME : DBUSERNAME
      DB_PASSWORD : DB PASS
      DB_DATABASE : DBDATABASENAME
      DB_SYNC : true
      JWT_SECRET : secret@123
      JWT_EXPIRESIN : 2d
      RESET_PASSWORD_URL : http://3.15.153.226:3000
    volumes:          
      - /auth/src/app/node_modules

  mail:
    build:
      context: ./mail
    command: npm run start:prod
    restart: always
    ports:
      - "5200:5200"
    depends_on:
      - db
      - auth
      - gateway      
    environment:
      EMAIL_HOST : smtp.gmail.com
      EMAIL_USER : SMTP-email-pass
      EMAIL_PASSWORD : smtp-password
    volumes:          
      - /mail/src/app/node_modules



Gmail : SMTP : Simple Mail Transfer Protocol

Gmail : SMTP : Simple Mail Transfer Protocol

1. Go to google Gmail account setting 

    → Go to Forwarding and POP/IMAP 

    → Enabled IMAP access.

2. After go to : manage your google account 

    → Go to security page 

    → Less secure option is enable

3. Email smtp setting : 

    → Server name : smtp.gmail.com ,

    → Port : 587 for Gmail account,

    → Username and password google account

    → Sender name enter 

    → Save 

 

AWS SES : Simple Email Service

 


AWS SES : Simple Email Service

1. Download access key and secret key excel file.

2. Go to verified identity -> Create Identity -> Verify email received in email account and verified.

3. npm install aws-sdk

const AWS = require("aws-sdk");

const awsConfig = {
  accessKeyId: AWS_ACCESS_KEY_ID,
  secretAccessKey: AWS_SECRET_ACCESS_KEY,
  region: process. AWS_REGION,
};

const SES = new AWS.SES(awsConfig);

const sendEmail = async () => {

  try {
    //prepare email to send

    const params = {
      Source: "verifiedemailaddress@gmail.com"  //verified email address
      Destination: {
        ToAddresses: "to@gmail.com",
      },
      Message: {
        Subject: {
          Charset: "UTF-8",
          Data: "OTP Verification",
        },
        Body: {
          Html: {
            Charset: "UTF-8",
            Data: `<h1>Your verification code is 12345</h1>`,
          },
        },
      },
    };

    const emailSent = SES.sendEmail(params).promise();
    emailSent
      .then((data) => {
        console.log(data);
      })
      .catch((err) => {
        console.log(err);
      });
  } catch (error) {
    console.log(error);
  }
};

module.exports = sendEmail;