Passport: TypeError: Cannot set property ‘user’ of undefined [closed]

When logged in it returns this error:

[SERVER] TypeError: Unable to set the 'user' property of undefined
[SERVER] a node_modulespassport-remember-menode_modulespassportlibpassporthttprequest.js:45:35
[SERVER] a node_modulespassportlibauthenticator.js:292:43)
[SERVER] a node_modulespassportlibauthenticator.js:301:7)
[SERVER] a configurepassport.js:55:5
[SERVER] a pass node_modulespassportlibauthenticator.js:309:9)
[SERVER] a Authenticator.serializeUser (node_modulespassportlibauthenticator.js:314:5)
[SERVER] a IncomingMessage.req.login.req.logIn (node_modulespassport-remember-menode_modulespassportlibpassporthttprequest.js:43:29)
[SERVER] a app.js:477:13.
[SERVER] a Strategy.strategy.success (node_modulespassportlibmiddlewareauthenticate.js:222:18)
[SERVER] a verified (node_modulespassport-locallibstrategy.js:83:10)
[SERVER] a callback (node_modules_passport-localstrategy.js:83:10)
[SERVER] a Child.<anonymous> (routescommonpermissions.js:594:7)
[SERVER] a Child.tryCatcher (node_modulesbluebirdjsreleaseutil.js:16:23)
[SERVER] a Promise._settlePromiseFromHandler (node_modulesbluebirdjsreleasepromise.js:547:31)
[SERVER] to Promise._settlePromise (node_modulesbluebirdjsreleasepromise.js:604:18)
[SERVER] to Promise._settlePromise0 (node_modulesbluebirdjsreleasepromise.js:649:10)

These are the versions of libraries:

“passport“:”^0.7.0”,
    “passport-local“:”^1.0.0”,
    “passport-remember-me": ‘0.0.1’,

the strange thing is that I have this problem after I made the project from scratch with git clone.
The project to my colleague works correctly, it only creates this problem when you create it clean and install the libraries from scratch.

Charts have extra padding when printed

I have a page with several charts made with AmCharts4 and I’m setting their height through CSS:

@media print {
    #year-month-chart,
    #cosphi-chart,
    #power-line-chart,
    #yearly-slots-chart 
    {
        height: 230px !important;
        padding: 0;
        margin: 0;
        font-size: 10px;
        line-height: 1;
    }
}

Here an example of one chart instantiated:

HTML:
<div id="cosphi-chart"></div>

JS:
var chart = am4core.create("cosphi-chart", am4charts.XYChart);

This is how they look with media emulation set to printer:

https://i.sstatic.net/IYdA64ZW.png

But when I print on PDF the charts look weird:

https://i.sstatic.net/oZWRc7A4.png

Any idea about this? I already printed AmCharts4 charts but never had this issue.

Create a measuring tool on a pdf editor

I’ve been tasked with the creation of a PDF editing tool in a web browser. In short, I need to be able to add lines, rectangles, circles, texts and be able to measure distance. My only restriction is to use open-sourced and free existing libraries or do it myself.

I’ve looked into it, saw several paid apps that would do what I need (and much more) such as apryse, so I guess it’s possible (doesn’t mean it’s easy …).

I found several way to edit PDF in a webapp, with PDF.js, or an angular version (I used a lot of angular in the past years, so this was a good start for me).

After simply launching an app with the latter option, I quickly realized this was different from the paid apps I saw earlier. Which means, there’s a lot to do. Creating lines or rectangles doesn’t sound that hard, I’ve worked with SVG a lot, and I guess I can figure out something similar for PDFs. My main focus is the measuring tool.

Before even trying to measure anything, I wondered if I could find in the DOM a line I drew. Well, I can. For example, it looks like this :

<div data-editor-rotation="0" class="inkEditor draggable disabled" id="pdfjs_internal_editor_3"
  tabindex="-1" data-l10n-id="pdfjs-ink" style="z-index: 4; left: 19.35%; top: 24.13%; width: 18.43%;
  height: auto; aspect-ratio: 5.38 / 1;" aria-label="Éditeur de dessin">
    <div class="resizers hidden">
        <div class="resizer topLeft" data-resizer-name="topLeft" tabindex="-1"></div>
        <div class="resizer topRight" data-resizer-name="topRight" tabindex="-1"></div>
        <div class="resizer bottomRight" data-resizer-name="bottomRight" tabindex="-1"></div>
        <div class="resizer bottomLeft" data-resizer-name="bottomLeft" tabindex="-1"></div>
    </div>
    <canvas height="74" width="393" class="inkEditorCanvas" data-l10n-id="pdfjs-ink-canvas"
      aria-label="Image créée par l’utilisateur·trice" style="visibility: visible;"></canvas>
    <div class="editToolbar hidden" role="toolbar"><div class="buttons">
        <button class="delete" tabindex="0" data-l10n-id="pdfjs-editor-remove-ink-button"
          title="Supprimer le dessin"></button>
    </div>
</div>

With a bit of work I could probably modify the ID to something I handle to classify if it’s a line, a rectangle, whatever, so I should be able to get any drawn element in my typescript part (at least that doesn’t sound like a problem to me).

The thing is, now I have this DOM element, but there is no tool provided to measure anything. So I started looking into “how to measure a dom element in cm or in”. Well, I didn’t find anything easy there. Getting the size in px isn’t a problem. But then converting px in cm … is the real deal I guess.

I saw that apryse lets you draw a line of a known distance for example, which then makes it possible to measure anything. I wonder how that works, since you can change the zoom so it’s not a fixed quantity of px that equals to 1 cm.

Should I store the zoom value, px size of the known-sized line and calculate the scale each time zoom change ? Doesn’t sound efficient to me. It seems everything I found use canvas to draw on the PDF, but I’m not very familiar with it, I tried to search for canvas tools to measure distance, but didn’t find anything that seemed to fit my case.

I’ve read few things about DPI, but it seems it’s not easy to get it from the web browser, or at least I’m not sure it would work in any browser. Also I read several case where people got confused between screen ratio, DPI, etc. So I’m a bit confused about all that tbh, now that I’ve read many things and their opposite.

I used an angular module for the example, but anything in js would be fine with me, it is not a requirement, just something I’m confortable with.

I guess, to sumerize what I need is to understand how to efficiently get then store a scale value, so that I can measure anything on a given PDF doc. In every PDF I use, there are object with known size in cm, so I can draw a line that match the object size. But then what about the zoom ? I don’t want to recalculate the scale every time I zoom in or out.

Having a bug with CldVideoPlayer in Next.js website

I am using CldVideoPlayer to playback video for my users. I have a component where I rendered the CldVideoPlayer and import to use anywhere I wanted to use it.
The error that I am getting is this:

Multiple instances of the same video detected on the
 page which may cause some features to not work.
Try adding a unique id to each player.

Here are my codes:

import "next-cloudinary/dist/cld-video-player.css";
import { CldVideoPlayer } from "next-cloudinary";

export function CloudinaryVideoPlayer(props: mediaPlayerAttributes) {
const { playerId, publicMediaId, width, height } = props;

 return (
 <div className={`w-full flex justify-center  flex-col `}>
  <div className={``}>
    <CldVideoPlayer
      id={playerId as string}
      src={publicMediaId}
      height={height}
      className=" rounded-lg outline-none"
    />
  </div>
  </div>
 );
}

This is where I used it so far:

export const SingleCourseView = ()=>{
 const httpReqeust = fetchAPI;

 return (
  <CloudinaryVideoPlayer
    publicMediaId={httpReqeust?.courseVideoPublicURL}
    playerId={httpReqeust?._id as string}
   />
  )  

}

Funny enough, I only have one video to view on this page. Yet it keeps saying multiple instance of the same video. Seems the Video component is rendering multiple times.
The id is unique.
I have also noticed that this error does not happen when you refresh the page. It happens when you navigate to the page from another page. If the navigation would lead to reload of the page, the error will not appear. So, it is a bug. I don’t know if there is a way around it. For now, I am using Next.js Link component and set target to blank to force reload of the page. But I would like a normal navigation to that page.

Ant Popover does not hide even ant-popover-hidden is applied

I am using antd version “^4.9.2”. Ant Popover component is displayed and it shows the pop up but when it hides ‘ant-popover-hidden’ is shown in the html tag in the elements section of chrome web debugging tool but style is not being applied. Look in the styles section of chrome web debugging tool and ‘ant-popover-hidden’ is missing.

What could be the reason ? Popover content never gets out of the screen as display style is never none.

Event onVisibleChange shows the correct result. When popover has to be removed it shows visible false and when popover becomes visible it shows the result as true.


const onVisibleChange = (visible:boolean) => {
      console.log(`Popover visible ${visible}`)
}

<Popover
      trigger="click"
      placement="bottom"
      ref={popoverRef}
      align={{ offset: [-2, 0] }}
      content={popoverContent}
      overlayClassName={styles.popover}
      onVisibleChange={onVisibleChange}
      animation=''
      transitionName=''
      >
      <div data-buyersellerRendererInside className={cx(styles.container)} data-popover={maxSizeLength}>
        <div className={styles.companyName}>{val[0]?.substring(0,5)}</div>
      </div>
    </Popover>

can any expert please provide what could be the issue?

Web Console Image

Unhandled Runtime Error Error: Element type is invalid. Received a promise that resolves to: undefined. Lazy element type must resolve to a class or

Can I get a suggestion for this fix, error which im getting

Unhandled Runtime Error

Error: Element type is invalid. Received a promise that resolves to: undefined. Lazy element type must resolve to a class or function.

Call Stack
Next.js
beginWork
./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js
runWithFiberInDEV
./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js
performUnitOfWork
./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js
workLoopSync
./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js
renderRootSync
./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js
performWorkOnRoot
./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js
performWorkOnRootViaSchedulerTask
./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js
MessagePort.performWorkUntilDeadline
./node_modules/next/dist/compiled/scheduler/cjs/scheduler.development.jsScreenshot of the error message

puppeteer launch browser with existing browser

I am using next js app, from UI i want open browser within my app ,

here is my code written in route.js

export async function POST(request: Request) {
    const { webUrl: userSearch } = await request.json();
    const headersList = headers();
    const origin = headersList.get('origin') || 'http://localhost:3000';

    if (!userSearch) {
        return NextResponse.json(
            { error: "Search parameter not provided" },
            { status: 400 }
        );
    }
    let browser;

    try {

         browser = await puppeteer.launch({
             headless: false,  
             defaultViewport: null,
             args: ['--start-maximized'] 
         });
        
        console.log(browser);
        const page = await browser.newPage();
        await page.goto(userSearch);

        return NextResponse.json({
            success: true,
            message: "Browser launched successfully",
            url: userSearch
        });
    }

     catch (error: any) {
        return NextResponse.json(
            { error: `An error occurred: ${error.message}` },
            { status: 200 }
        );
    } 
}

UI component page.js

const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setIsLoading(true);
    const res = await fetch("/launchBrowser", {
        method: "POST",
        body: JSON.stringify({ webUrl }),
        headers: {
            "Content-Type": "application/json",
        },
    });

};

Now test browser getting launch

I am looking to open this within my app http://localhost:3000

is any way there to do this

Style MUI date time picker popper dialog background

I am trying to change the color of the background of the MUI date time picker’s popper for desktop and mobile :

I want to change the black / grey background to lightgreen

I have tried to use ‘popper’, ‘mobilePopper’ and ‘desktopPopper’ but none of those selectors seem to work.

Here is what I have tried that does not work :

const popperSx : SxProps = {
    "& .MuiPaper-root" : {
        backgroundColor: 'lightgreen!important', // doest not work 
    }
}

const OurDateTimePicker = ({
    value,
    setValue,
    sx,
    name,
    label,
    clearable,
    disabled,
    helperText,
    onBlur,
    error
}: OurDateTimePickerProps) => {

    const [selectedDate, setSelectedDate] = useState<Dayjs | null>(dayjs(value))

    useEffect(() => {
        setSelectedDate(dayjs(value))
    }, [value])

    const handleSelectedDate = (newValue: Dayjs | null) => {
        setSelectedDate(newValue)
        if (newValue)
            setValue(new Date(newValue.format('YYYY-MM-DDTHH:mm:ss')))
    }

    const [cleared, setCleared] = useState<boolean>(false)

    useEffect(() => {
        if (cleared) {
            setValue(null)
            const timeout = setTimeout(() => {
                setCleared(false)
            }, 1500)

            return () => clearTimeout(timeout)
        }
        return () => { }
    }, [cleared])

    const handleBlurWrapper = (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {
        onBlur?.(event);
    }

    return (
        <Box sx={sx}>
            <LocalizationProvider
                dateAdapter={AdapterDayjs}
                adapterLocale={"fr"}
                localeText={frFR.components.MuiLocalizationProvider.defaultProps.localeText}>
                <DateTimePicker
                    name={name}
                    value={selectedDate}
                    onChange={handleSelectedDate}
                    sx={{ width: "100%" }}
                    label={label}
                    slotProps={{
                        field: { clearable: clearable, onClear: () => setCleared(true) },
                        textField: {
                            helperText: helperText,
                            error: error,
                            onBlur: handleBlurWrapper,
                        },
                        mobilePaper: popperSx,
                        desktopPaper: popperSx,
                        popper: popperSx

                    }}
                    disabled={disabled}
                />
            </LocalizationProvider>
        </Box>
    )
}

Sharing the same price scale for both left and right in lightweight charts

I am drawing some lines to visualize the time of long/short position.
My goal is to position label (P&L text) **to the left border of the chart**.

const chart = createChart(chartContainerRef.current, {
  layout: {
    background: { type: ColorType.Solid, color: 'transparent' },
    textColor: '#333',
  },
  grid: {
    vertLines: { color: '#444' },
    horzLines: { color: '#444' },
  },
  width: chartContainerRef.current.clientWidth,
  height: 400,
  timeScale: {
    timeVisible: true,
    secondsVisible: false,
  },
});


// Create order line
const orderLine = chart.addLineSeries({
  color: trade.action === 'LONG' ? '#26a69a' : '#ef5350',
  lineWidth: 2,
  lineStyle: LineStyle.Solid,
  title: `PnL:${pnl?.toFixed(4)}`,
  priceScaleId: 'left',
});

Setting priceScaleId to left does a trick, but the problem is, left and right have different price scales.
This results in lines being drawn lower or higher than its original position.
How can I have the same price scaling for both left and right, or is there any other solution?

Appreciate your help!

Lightweight charts

Using JavaScript how do I enclose the text of an tag with a if a parent has a certain class

I have the following code

<div class="team-grid">
    <div class="cssgrid-wrapper">
        <div class="cssgrid-container">
            <div class="tmb"> 
                <div class="t-inside "> 
                    <div class="t-entry-text">
                        <div class="t-entry-text-tc"> 
                            <div class="t-entry"> 
                                <p class="t-entry-meta"> 
                                    <span class="t-entry-category t-entry-tax"> 
                                        <a href="#">Category one</a>
                                    </span> 
                                </p> 
                            </div> 
                        </div> 
                    </div> 
                </div> 
            </div>
        </div>
        <div class="tmb"> 
            <div class="t-inside "> 
                <div class="t-entry-text">
                    <div class="t-entry-text-tc"> 
                        <div class="t-entry"> 
                            <p class="t-entry-meta"> 
                                <span class="t-entry-category t-entry-tax"> 
                                    <a href="#">Category two</a>
                                </span> 
                            </p> 
                        </div> 
                    </div> 
                </div> 
            </div> 
        </div>
    </div>
</div>

and I’d like to use javascript to enclose every tag’s text with a that has the class ‘hide’ if the a tag has a grandparent with the class ‘team-grid’ and parent with the class ‘t-entry-category’.

So in the above example the result would be

<div class="team-grid">
    <div class="cssgrid-wrapper">
        <div class="cssgrid-container">
            <div class="tmb"> 
                <div class="t-inside "> 
                    <div class="t-entry-text">
                        <div class="t-entry-text-tc"> 
                            <div class="t-entry"> 
                                <p class="t-entry-meta"> 
                                    <span class="t-entry-category t-entry-tax"> 
                                        <a href="#"><span class="hide">Category one</span></a>
                                    </span> 
                                </p> 
                            </div> 
                        </div> 
                    </div> 
                </div> 
            </div>
        </div>
        <div class="tmb"> 
            <div class="t-inside "> 
                <div class="t-entry-text">
                    <div class="t-entry-text-tc"> 
                        <div class="t-entry"> 
                            <p class="t-entry-meta"> 
                                <span class="t-entry-category t-entry-tax"> 
                                    <a href="#"><span class="hide">Category two</span></a>
                                </span> 
                            </p> 
                        </div> 
                    </div> 
                </div> 
            </div> 
        </div>
    </div>
</div>

any help would be appreciated.

Unable to upload image to aws s3 from vuejs and express and paste the url into database

<template>
  <LeftSideBar></LeftSideBar>
  <div class="create-post">
    <h2>Create a New Post</h2>
    <!-- Form for post data -->
    <form @submit.prevent="submitPost">
      <!-- Post Title -->
      <div>
        <label for="title">Title</label>
        <input
            type="text"
            id="title"
            v-model="postData.title"
            placeholder="Enter post title"
            required
        />
      </div>

      <!-- Post Caption (Thumbnail) -->
      <div>
        <label for="caption">Thumbnail Caption</label>
        <input
            type="text"
            id="caption"
            v-model="postData.thumbnailCaption"
            placeholder="Enter thumbnail caption"
        />
      </div>


      <!-- Blocks -->
      <div v-for="(block, index) in postData.blocks" :key="index" class="block-section">
        <label>Block {{ index + 1 }}</label>
        <div v-if="block.type === 'text'">
                    <textarea
                        v-model="block.content"
                        @input="autoResize"
                        placeholder="Enter text content"
                    ></textarea>
        </div>
        <div v-if="block.type === 'image'">
          <input
              type="file"
              @change="handleImageUpload($event, index)"
              accept="image/*"
              name="content"
          />
          <img v-if="block.previewUrl" :src="block.previewUrl" alt="Image Preview" class="preview-image" />
        </div>
      </div>

      <!-- Add Block Buttons -->
      <button type="button" @click="addTextBlock">Add Text Block</button>
      <button type="button" @click="addImageBlock">Add Image Block</button>

      <!-- Submit and Save Draft Buttons -->
      <button type="submit">Create Post</button>
      <button type="button" @click="saveDraft">Save Draft</button>
    </form>

    <!-- Modal for confirming post creation -->
    <div v-if="showModal" class="modal">
      <div class="modal-content">
        <p>Are you sure you want to submit this post?</p>
        <button @click="submitPost">Yes, Submit</button>
        <button @click="showModal = false">Cancel</button>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios';
import LeftSideBar from '@/components/LeftSideBar.vue';
import { mapState } from 'vuex';

export default {
  name: 'CreatePost',
  components: {
    LeftSideBar,
  },
  computed: {
    ...mapState('account', {
      isLoggedIn: state => state.status.loggedIn,
      userId: state => state.user ? state.user.id : null
    })
  },
  data() {
    return {
      postData: {
        title: '',
        caption: '',
        group_id: null,
        thumbnailCaption: '',
        blocks: []
      },
      fontSize: 16,
      currentBlock: { type: '', content: '' },
      showModal: false
    };
  },
  mounted() {
    if (!this.isLoggedIn) {
      alert('Please log in to create a post.');
      this.$router.push('/login');
    }
  },
  methods: {
    async submitPost() {
      this.showModal = false;
      try {
        // Create the main post first
        const postResponse = await axios.post('http://localhost:5000/post/create-post', {
          group_id: this.postData.group_id,
          user_id: sessionStorage.getItem('user_id'),
          title: this.postData.title,
          caption: this.postData.thumbnailCaption
        });
        const postId = postResponse.data.post_id;

        // Upload each block
        // Upload each block
        for (let [index, block] of this.postData.blocks.entries()) {
          // Prepare form data for image blocks
          const formData = new FormData();
          formData.append('post_id', postId);  // The ID of the post
          formData.append('type', block.type); // 'text' or 'image'
          formData.append('order', index + 1); // Order of the block

          if (block.type === 'image') {
            // Append the image file for upload to S3
            formData.append('content', block.file); // File to upload
          } else {
            // For text blocks, directly append content
            formData.append('content', block.content); // Content for text
          }

          // Send request to create the block
          await axios.post('http://localhost:5000/post/create-post-block', formData, {
            headers: {
              'Content-Type': 'multipart/form-data' // Ensure correct content type for file upload
            }
          });
        }
        alert("Post created successfully");
        this.$router.push('/');
      } catch (error) {
        console.error("Failed to create post:", error);
        alert("An error occurred while creating the post.");
      }
    },
    handleImageUpload(event, index) {
      const file = event.target.files[0];
      if (file) {
        const reader = new FileReader();
        reader.onload = (e) => {
          this.$set(this.postData.blocks[index], 'previewUrl', e.target.result);
        };
        this.$set(this.postData.blocks[index], 'file', file); // Store the file for later upload
        reader.readAsDataURL(file);
      }
    },
    addTextBlock() {
      this.postData.blocks.push({ type: 'text', content: '' });
    },
    addImageBlock() {
      this.postData.blocks.push({ type: 'image', content: '', previewUrl: '', file: null });
    }
  }
};
</script>

This is the code for my post create page in a blog-like socila network which create one block at a time to integrate post and text between each other. I am having a problem, the system works normal if a block is text but if it is an image, it does not put the url of the file in s3 into the database

THis is my api

exports.createPostBlock = async (req, res) => {
    const { post_id, type, order } = req.body;

    try {
        // Ensure required fields are present
        if (!post_id || !order) {
            return res.status(400).json({ error: 'post_id and order are required fields' });
        }

        let content = null;

        // If type is 'image', handle the file upload
        if (type === 'image' && req.file) {
            content = req.file.location; // The file URL returned from S3 or local storage
        } else if (type === 'text') {
            content = req.body.content; // Assuming content is passed for text posts
        }

        // Create PostBlock in the database
        const postBlock = await Post_block.create({
            post_id,
            type,
            content,
            order,
        });

        res.status(201).json({ message: 'Post block created successfully', postBlock });
    } catch (error) {
        console.error('Error creating post block:', error);
        res.status(500).json({ error: 'Error creating post block', details: error.message });
    }
};

This is my middleware and route

const multer = require('multer');
const multerS3 = require('multer-s3');
const AWS = require('aws-sdk');
const {S3Client} = require("@aws-sdk/client-s3");
require('dotenv').config();
// Initialize AWS S3
const s3 = new S3Client({
    region: 'ap-southeast-1',
    credentials: {
        accessKeyId: '*hidden',
        secretAccessKey: '*hidden'
    },
});

// Set up multer storage configuration using S3
const storage = multerS3({
    s3: s3,
    bucket: '*hiddden',  // Ensure the AWS S3 bucket name is in your .env file
    key: (req, file, cb) => {
        cb(null, `uploads/${Date.now()}-${file.originalname}`);
    }
});

// Set up multer with the storage configuration
const image_upload = multer({ storage: storage });

// Export the upload middleware to be used in routes
module.exports = image_upload;

router.post('/create-post-block', postController.createPostBlock,upload.single('content'))

The APIs is successfully tested using postman

I tried everything, attaching the file directly to the api, uploading the image first…

Hashing with sha256 when sending user_data to GA4, Google ads, etc

tl;dr: Should there be a sha256_ prefix to city, regon, postal code, country, and should I hash them or not?

—- details
I am wondering wether google doesn’t consider city, region and postal code a sensitive information or the docs are incomplete. Judging by the second example, I don’t need to hash even street address. And yet I believe I should hash everything…
[Using smarty in the examples]

                gtag('set', 'user_data', {
                    "sha256_email_address": "{hash('sha256', $order_info.email)}",
                    "address": {
                        "sha256_first_name": "{hash('sha256', $order_info.firstname)}",
                        "sha256_last_name": "{hash('sha256', $lastname)}",
                        "sha256_street": "{hash('sha256', $address)}",
                        "sha256_city":"{hash('sha256', $city)}",
                        "sha256_region":"{hash('sha256', $country)}",
                        "sha256_postal_code": "{hash('sha256', $zipcode)}",
                        "sha256_country": "{hash('sha256', $country)}"
                    }
                });

**Resources: **
https://support.google.com/analytics/answer/14171598
https://developers.google.com/analytics/devguides/collection/ga4/uid-data

"sha256_city":"{hash('sha256', $city)}",
vs
"city":"{hash('sha256', $city)}",
vs
"city":"{$city}",

Can I call an anonymous function inside a tag linked to an external js file?

HTML File(firstHTML.html)

<!DOCTYPE html>
<html>
<body>

<h2>My First Web Page</h2>
<p id="demo">First Paragraph</p>
<p id="demo2">Second Paragraph should be something different</p>
<script src="myScript.js">
    show3();
</script>
</body>
</html>

JavaScript File(myScript.js)

let show3 = function() {
document.getElementById(‘demo2′).innerHTML=’I am trying to change the second paragraph using an anonymous function in an external JS file’;

};

I was expecting for the show() function to run since it’s below the

tag. I am still learning about javascript scope so it’s entirely possible that anonymous functions don’t have a global scale and so my function won’t run but why is my question. Thank you all in advance.

Pagination for nested accordion in AngularJS

Could someone assist me with adding pagination within an accordion? I’d really appreciate the help!

HTML Code:

<!DOCTYPE html>
<html ng-app="simpleApp">
   <head>
      <title>Simple AngularJS Example</title>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
   </head>
   <body ng-controller="SimpleController">
      <div class="accordion-item" ng-repeat="item in pgmg" ng-class="{'active': item.isOpen}">
         <div class="accordion-header" ng-click="toggle(item)">
            <h4>{{item.automationState}}</h4>
         </div>
         <div class="accordion-content">
            <table class='table table-striped'>
               <thead class='thead-dark'>
                  <tr>
                     <th>Migration context</th>
                     <th>CHG number</th>
                     <th>Instance Name</th>
                  </tr>
               </thead>
               <tbody>
                  <tr ng-repeat="pgmgObj in getPaginatedData(item)">
                     <td>{{pgmgObj.migrationContext}}</td>
                     <td>{{pgmgObj.chg}}</td>
                     <td>{{pgmgObj.instanceName}}</td>
                  </tr>
               </tbody>
            </table>
            <!-- Pagination controls for each item -->
            <uib-pagination 
               total-items="item.details.length" 
               ng-model="item.currentPage" 
               items-per-page="itemsPerPage" 
               max-size="5" 
               boundary-links="true">
            </uib-pagination>
         </div> <!--accordion-content-->
      </div> <!--accordion-item-->
   </body>
</html>

JavaScript Code:

// Define the AngularJS module and controller
angular.module('simpleApp', [])
  .controller('SimpleController', function($scope) {
    $scope.pgmg = [
      {
        automationState: "Scheduled",
        isOpen: true,
        currentPage: 1,
        details: [
          { migrationContext: "000123", chg: "chg123", instanceName: "test123" },
          { migrationContext: "000346", chg: "chg346", instanceName: "test346" },
          { migrationContext: "000456", chg: "chg456", instanceName: "test456" },
          { migrationContext: "000789", chg: "chg789", instanceName: "test789" },
          { migrationContext: "000101", chg: "chg101", instanceName: "test101" },
          { migrationContext: "000202", chg: "chg202", instanceName: "test202" }
        ]
      },
      {
        automationState: "In Progress",
        isOpen: false,
        currentPage: 1,
        details: [
          { migrationContext: "000123", chg: "chg123", instanceName: "test123" },
          { migrationContext: "000346", chg: "chg346", instanceName: "test346" },
          { migrationContext: "000456", chg: "chg456", instanceName: "test456" },
          { migrationContext: "000789", chg: "chg789", instanceName: "test789" },
          { migrationContext: "000101", chg: "chg101", instanceName: "test101" },
          { migrationContext: "000202", chg: "chg202", instanceName: "test202" }
        ]
      }
    ];
    
    // Function to toggle accordion item open/closed state
    $scope.toggle = function(item) {
        item.isOpen = !item.isOpen;
    };
  
     $scope.itemsPerPage = 3;
    $scope.getPaginatedData = function(item) {
        const startIndex = (item.currentPage - 1) *     $scope.itemsPerPage;
        const endIndex = startIndex + $scope.itemsPerPage;

        return item.details.slice(startIndex, endIndex);

    };
  
  });

I’m including the currentPage value in my data object so that each accordion’s pagination starts from the correct page. In the HTML section, I’m calling getPaginatedData and passing ‘item’ to it.

[code] https://codepen.io/sreekarvsp/pen/ExqMKvN

Separating Header and Footer from index.html

I’m currently building my website using HTML, CSS and JS. I am trying to separate my header and footer from my index.html, but it doesn’t seem to be working as it would be if they were in the same file, index.html. Can someone please help me?
This is how it is supposed to look like (this is what happens when I merge them all into index.html) Pic #1

This is how the webpage appears when I separate the header and footer from the index.html (the header no longer freezes at the top of the screen and animation for the footer stops working):Pic#2
Here is my HTML code:

<header class="header">
<div class="header-content">
    <div class="logo">RV</div>
    <div class="menu-icon" id="menu-icon">
        <div class="bar"></div>
        <div class="bar"></div>
        <div class="bar"></div>
    </div>
    <nav class="nav" id="navMenu">
        <ul class="nav-list"> 
            <li class="nav-link"> <a href="index.html">HOME</a></li>
            <li class="nav-link"> <a href="projects.html">PROJECTS</a></li>
            <li class="nav-link"> <a href="experience.html">EXPERIENCE</a></li>
            <li class="nav-link"> <a href="others.html">OTHERS</a></li>
        </ul>
    </nav>
</div>
</header>

This is my Footer.html

<div class="page-wrapper">
<div id="waterdrop"></div>
<footer>
  <div class="footer-top">
    <div class="footer-container">
        
        <div class="footer-icons">
            <a href="https://www.linkedin.com/in/rithvik-vaddadi-8469471a9/"> <img class="linkedin" src="Images/linkedin.png" alt="linkedin"></a>
            <a href="https://www.linkedin.com/in/rithvik-vaddadi-8469471a9/"> <img class="telegram" src="Images/telegram.png" alt="telegram"></a>
            <a href="https://www.instagram.com/rithvik_amars/"><img class="insta" src="Images/instagram.png" alt="instagram"></a>
          
        </div>
      
    </div>
  
    <div class="copyright">
      <p style="color: black;">
        2024 &copy by Rithvik Amar
      </p>
    </div>
  </div>
</footer>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" 
</script>
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script src="https://daniellaharel.com/raindrops/js/raindrops.js"></script>
<script> jQuery('#waterdrop').raindrops({color:'#989090',canvasHeight:150, density: 0.1, frequency: 10});</script>

This is my index.html code:

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./styles.css"/>
<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet'>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&family=Roboto:wght@400;500&display=swap" rel="stylesheet">
<title>HomePage</title>
<script>
    // Function to include an external file
    function includeHTML() {
        const elements = document.querySelectorAll("[data-include]");
  
        elements.forEach(el => {
            const file = el.getAttribute("data-include");
            if (file) {
                fetch(file)
                    .then(response => {
                        if (response.ok) return response.text();
                        throw new Error("Network response was not ok.");
                    })
                    .then(html => {
                        el.innerHTML = html;
                    })
                    .catch(err => console.error("There was a problem including the HTML file:", err));
            }
        });
    }
  
    document.addEventListener("DOMContentLoaded", includeHTML);
  </script>
</head>
<body>
<div class="page">
    <div data-include="header.html"></div>
    
    <div class="about">
        <div class="about-text">
            <h1 class="title">RITHVIK VADDADI</h1>
            <span class="Intro">Cyber Security Enthusiast | Toastmasters | Cardistry</span>
        </div>
        <div class="arrow-wrap">
            <div class="arrow-down arrow"></div>
            <div class="arrow-down arrow"></div>
        </div>
      </div>

      <div class="overview">
        <h2>About me</h2>
        <div class="OV">
            <img src="Images/My PFP.jpg" alt="Avatar" class="Avatar">
            <div class="text-buttons">
                <p class="description">Hello, I am Rithvik Vaddadi, a current NSF with a diploma in Cyber Security and Digital Forensics. Drawn to the world of computers, I aspire to make people's lives easier and protect them from cyber attacks with the help of technology around us. As a problem solver, I am known to use my creative and critical thinking skills when providing solutions in my past leadership roles and projects. When involved in projects, I tend to notice people's strengths and weaknesses and assign them to roles where their potential would be fully maximized in the project. When my mind is fixed on a goal, I dedicate my energy and focus to achieving the goal.</p>
                <div class="buttons">
                    <a href="https://docs.google.com/document/d/1ZjzHjOgWy2RH1Lz27aZAih7ZEqYFOU-0mNnstJ93LtU/edit?usp=sharing" target="_blank"></a>
                        <button>View My Resume</button>
                    </a>
                    <a href="https://www.linkedin.com/in/rithvik-vaddadi-8469471a9/" target="_blank">
                        <button>View My LinkedIn</button>
                    </a>
                </div>
            </div>
        </div>
        <section class="education-section">
          <h2>My Education Journey</h2>
          <div class="cards-container">
              <div class="card" id="army-card">
                  <div class="card-inner">
                      <div class="card-front">
                          <h3>Army</h3>
                      </div>
                      <div class="card-back">
                          <h3>SAF Singapore Armed Forces</h3>
                          <p>Vocation: 5SIR Infantry Soldier as a General Purpose Machine Gun (GPMG) Gunner and Platoon 2ic <br>
                            Rank: Corporal <br>
                            ORD Date: 2nd May 2025<br>
                            Overseas involvement: Brunei, Malaysia, Australia. <br>
                            Achievements: Due to my exceptional combat fitness and leadership, I was chosen to represent my battalion in a Joint Adventure Training (JAT) with the Malaysian Army Rangers. <br>
                            Skills: Proficient in handling GPMG, SAR21, and LMG. Trained in drone flying. (DJI Mavick Pro, Vesper, Cetus)
                          </p>
                          <div class="gallery-wrap">
                            <img src="Images/back.png" class="backBtn">
                            <div class="gallery">
                                <div>
                                    <span><img src="Images/Army1.jpg"></span>
                                    <span><img src="Images/Army2.jpg"></span>
                                    <span><img src="Images/Army4.jpg"></span>
                                </div>
                                <div>
                                    <span><img src="Images/Army3.jpg"></span>
                                    <span><img src="Images/Army5.jpg"></span>
                                    <span><img src="Images/My PFP.jpg"></span>
                                </div>
                            </div>
                            <img src="Images/front.png" class="nextBtn">
                          </div>
                          <span class="close-btn"><img src="Images/X.png" alt="close"></span>
                      </div>
                  </div>
              </div>
              <div class="card" id="poly-card">
                  <div class="card-inner">
                      <div class="card-front">
                          <h3>Polytechnic</h3>
                      </div>
                      <div class="card-back">
                          <h3>Ngee Ann Polytechnic</h3>
                          <p>Course: Cyber Security and Digital Forensics<br>
                            CCAs: Vice-President and Student Advisor of NP's Toastmasters Club, Head of Logistics for NP's ICTSociety, Tchoukball<br>
                            Achievements: I led a 2-hour group focus session with the Minister of Education, Mr Chan Chun Sing, about the future of Singapore's education, housing, etc. 
                            Showcased my capstone project at Singapore International Cyber Week X Govware (SICW 2022).
                            Spearheaded a YEP-GO overseas cross-cultural program with a school in Ladakh, India for a week.
                            </p>
                          <div class="gallery-wrap">
                            <img src="Images/back.png" class="backBtn">
                            <div class="gallery">
                                <div>
                                    <span><img src="Images/Dip2.jpg"></span>
                                    <span><img src="Images/Dip5.jpg"></span>
                                    <span><img src="Images/Dip6.jpg"></span>
                                </div>
                                <div>
                                    <span><img src="Images/Dip3.jpg"></span>
                                    <span><img src="Images/Dip1.jpg"></span>
                                    <span><img src="Images/Dip7.jpg"></span>
                                </div>
                            </div>
                            <img src="Images/front.png" class="nextBtn">
                          </div>
                          <span class="close-btn"><img src="Images/X.png" alt="close"></span>
                        </div>
                    </div>
              </div>
              <div class="card" id="school-card">
                  <div class="card-inner">
                      <div class="card-front">
                          <h3>Secondary School</h3>
                      </div>
                      <div class="card-back">
                        <h3>Bukit Batok Secondary School</h3>
                        <p>Stream: Express double science (Physics and Chemistry)<br>
                          O-Level L1R5: 10 L1R4: 7<br>
                          CCAs: Badminton (Vice-Captain), Student Council (Vice President), Lewis House Captain
                          Achievements: I attended a photoshoot with my school's principle for our school website and magazine. This event was a testament to the contributions and impact I made in the school's community. Involved in many volunteer programs such as donating rice, beach clean-ups, etc.

                        </p>
                        <div class="gallery-wrap">
                            <img src="Images/back.png" class="backBtn">
                            <div class="gallery">
                                <div>
                                    <span><img src="Images/Secondary1.jpg"></span>
                                    <span><img src="Images/Secondary2.jpg"></span>
                                    <span><img src="Images/Secondary3.jpg"></span>
                                </div>
                                <div>
                                    <span><img src="Images/Secondary4.jpg"></span>
                                    <span><img src="Images/Secondary5.jpg"></span>
                                    <span><img src="Images/Secondary6.jpg"></span>
                                </div>
                            </div>
                            <img src="Images/front.png" class="nextBtn">
                          </div>
                        <span class="close-btn"><img src="Images/X.png" alt="close"></span>
                      </div>
                  </div>
              </div>
          </div>
      </section>
      <div data-include="footer.html"></div>
      
</div>
<script src="app.js"></script>
</body>
</html>

This is my styles.CSS code:

 *{
margin: 0;
padding: 0;
box-sizing: border-box;
}

.page{
position: relative;
background: #e2e2e2;
height: 300vh;
}

.logo{
font-size: 22px;
}

.header{
color: white;
background: transparent;
position: sticky;
z-index: 2;
top: 0;
transition: 0.3s ease-in-out;
height: 80px;
}

.scrolled{
height: 50px;
background: black;
transition: .3s ease-in-out;

}

.header-content{
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1100px;
margin: 0 auto;
height: 100%;
padding: 0 40px;
}

.nav{
display: flex;
width: 40%;
}

.nav-list{
list-style: none;
display: flex;
justify-content: space-between;
width: 100%;
flex-wrap: wrap;
gap: 20px;
}

.nav-link a{
color: white;
text-decoration: none;
border-bottom: 2px solid transparent;
transition: 0.3s;
}

.nav-link a:hover{
border-bottom: 2px solid white;
transition: 0.3s;
}

.menu-icon{
display: none;
flex-direction: column;
cursor: pointer;
}

.menu-icon .bar{
width: 25px;
height: 3px;
background-color: red;
margin: 4px 0;
transition: 0.4s;
}

@media (max-width:768px){
.nav{
    display: none;
    flex-direction: column;
    background-color: black;
    width: 100%;
    position: relative;
    top: 80px;
    left: 0;
    text-align: center;
    }
.nav-list{
    flex-direction: column;
    width: 100%;
}
.nav-link a{
    padding: 12px;
    border-bottom: 1px solid white;
    width: 100%;
    display: block;
}
.menu-icon{
    display: flex;
}
.nav.show{
    display:flex;
}
}


.about{
background-image: url(Images/CardistryBGD2.jpg);
background-size: cover;
height: 100vh;
position: relative;
top: -80px;
z-index: 1;
display: flex;
justify-content: center;
align-items:center;
flex-direction: column;
}

.about-text{
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}

.title{
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
color:white;
font-size: 9vw;
}

.Intro{
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
font-size: 1.5vw;
color: white;
margin-top: 10px;
}

.arrow-wrap {
position: absolute;
bottom: 30%;
left: 50%;
transform: translate(-50%, -25px);
-webkit-animation: arrow 0.5s 1s infinite ease-out alternate;
animation: arrow 0.5s 1s infinite ease-out alternate;
text-align: center;
}


.arrow {
position: relative;
padding: 15px;
border-left: solid 5px red;
border-bottom: solid 5px whitesmoke;
display: block;
}

.arrow-down {
transform: rotate(-45deg);
position: relative;
margin-top: -15px;
}

@keyframes arrow {
0% {
  bottom: 0px;
}
100% {
  bottom: 10px;
}
}

 /* Hover effect */
 .arrow-wrap:hover {
animation-play-state: paused;
}

/* Responsive styling for mobile screens */
@media (max-width: 768px) {
/* Place arrow differently on mobile */
.arrow-wrap {
    bottom: 30px;
}
}

h2{
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
color: white;
font-size: 3vw;
margin: 8px;
padding: 30px;
}

.Avatar{
vertical-align: middle;
width: 145px;
height: 140px;
border-radius: 50%;
margin-left: 15px;
}

.text-buttons{
display: flex;
flex-direction: column;
}

.overview{
background-image: url(Images/CardBG.jpg);
background-size: cover;
margin: -80px 0 0 0;
padding:0;
height: auto;
display: flex;
justify-content: center;
align-items:center;
flex-direction: column;
 

}

.OV{
display: flex;
align-items: flex-start;
max-width: 1150px;
color: white;
font-family: 'Montserrat';
text-align: left;
}

.description{
margin-left: 25px;
font-size: 1.2em;
}

.buttons{
display: flex;
gap: 20px;
margin-top: 20px;
}

button{
background: rgb(165, 1, 1);
color: #fff;
font-weight: 600;
border: none; 
border-radius: 12px;
/*     height: 50px;
width: 200px;  */
padding: 10px 20px;
font-size: 18px;
font-family: 'Montserrat';
margin-top: 20px;
box-shadow: 0px 4px 6px rgba(0,0,0,0.1);
transition: background-color 0.3s ease, transform 0.2s ease;
cursor: pointer;
}

button:hover{
background-color: #8a0000;
transform: translateY(-2px); 
box-shadow: 0px 6px 8px rgba(0,0,0,0.2);
}

@media (max-width: 768px) {
.overview {
    padding: 0px;
}

.OV {
    flex-direction: column;
    text-align: center;
    align-items: center;
}

.content{
    flex-direction: column;
}

.Avatar {
    margin-left: 0;
    margin-bottom: 20px;
    width: 120px;
    height: 120px;
}

.description {
    margin-left: 0;
    font-size: 4vw;
}

.buttons{
    flex-direction: column;
    align-items: center;
}

button{
    width: 150px;
    height: auto;
}
}

@media (max-width: 480px) {
.OV{
    align-items: center;
}

h2 {
    font-size: 6vw;
}

.description {
    font-size: 5vw;
}

.Avatar {
    margin: 0;
    width: 100px;
    height: 100px;
}

button{
    width: 100%;
    height: 16px;
    padding: 10px;
}
.buttons{
    align-items: center;
}
}


/* Section Styles */
.education-section {
padding: 20px 20px;
color: white;
text-align: center;
}

.cards-container {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
margin-top: 20px;
margin-bottom: 0;
}

/* Card Styles */
.card {
width: 300px;
height: 400px;
perspective: 1000px; 
margin: 20px;
transition: transform 0.3s ease box-shadow 0.3s ease;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
position: relative;

}

/* Hover Animation */
.card:hover {
transform: scale(1.05); /* Slight jump effect */
box-shadow: 0px 12px 24px rgba(255, 255, 255, 0.3);
}

/* Card Flip Animation */
.card-inner {
position: relative;
width: 100%;
height: 100%;
max-width: 1000px;
margin: 0 auto;
transform-style: preserve-3d;
transition: transform 0.8s ease;
cursor: pointer;
border-radius: 15px;
box-shadow: none;
font-family: Arial, sans-serif;
line-height: 1.6;
letter-spacing: 0.5px;
color: #f1f1f1;
}

.card-front, .card-back {
box-shadow: none;
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden; /* Hide the back while flipping */
border-radius: 10px;
background-color: #1e1e1e;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Roboto', sans-serif;
}


.card-front {
background: linear-gradient(135deg, #ac0101 0%, #941616 100%); /* Gradient */
color: white;
font-size: 1.5em;
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
text-align: center;

}
/* Back Card Design with Image Background */
.card-back {
background-image: url('your-image-back.jpg'); /* Replace with your image */
background-size: cover;
background-position: center;
transform: rotateY(180deg);
padding: 30px;
font-size: 1em;
color: #ddd;
backface-visibility: hidden;
display: flex;
flex-direction: column;
justify-content: flex-start; /* Align items from the top */
align-items: center; /* Center the items horizontally */
border-radius: 15px;
position: relative;
transition: background 0.5s ease;
}

.card-inner h1{
font-size: 24px;
font-weight: bold;
margin-bottom: 15px;
text-align: center;
}


/* Style for the h3 element (Title) */
.card-back h3 {
font-size: 1.8em;
color: #ffffff;
margin-bottom: 20px;
text-align: center;
width: 100%; /* Ensure it takes up full width */
position: absolute;
top: 30px; /* Adjust this value to control the top spacing */
left: 50%;
transform: translateX(-50%); /* Center horizontally */
}

/* Style for paragraph or other content */
.card-back p {
font-size: 1.2em;
text-align: left;
margin-top: 80px; /* Ensure it's below the h3 title */
z-index: 1;
width: 100%;
padding: 0 20px;
}

.card-inner.flip {
transform: rotateY(180deg);
}

/* Expand animation */
.card.expand {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
background-color: transparent;
transform: none;
transition: width 0.5s ease, height 0.5s ease;
box-shadow: none;
}



.card-back .close-btn {
position: absolute;
top: 15px;
right: 15px;
background-color: transparent;
border: none;
color: white;
font-size: 0.5em;
cursor: pointer;
font-weight: bold;
z-index: 1;
}

/* Media Queries for responsiveness */
@media (max-width: 768px) {
.cards-container {
    flex-direction: column;
    align-items: center;
}

.card {
    width: 80%;
    height: auto;
}
}

.gallery{
width:600px;
display:flex;
overflow-x: scroll;
}

.gallery div{
width: 100%;
display: grid;
grid-template-columns: auto auto auto;
grid-gap: 30px;
padding: 10px;
flex:none;
}

.gallery div img{
width:100%;
/* filter:grayscale(100%); */
transition: tranform 0.5s;
}

.gallery::-webkit-scrollbar{
display:none;
}

.gallery-wrap{
display:flex;
align-items:center;
justify-content: center;
margin: 2% auto;
}

.backBtn, .nextBtn{
width:50px;
cursor: pointer;
margin: 40px;
}

.gallery div img:hover{
transform: scale(1.1);
}

.footer-top {
text-align: center;
background-size: cover;
background-position: center;
padding: 30px 0px;
font-family: rubik;
margin-top: 0;

}
.page-wrapper
{
position: relative;
bottom: 0;
width: 100%;
z-index: 11111;

}

.footer-top, .footer-bottom {
background-color: #989090;

}

footer p, footer strong, footer b, footer {
color: #ffffff;
}

#waterdrop {
height: 80px;
}

#waterdrop canvas {
bottom: -70px !important;
}

.footer-site-info
{
padding-top: 10px;

}

footer {
text-align: center;
}

.footer-container {
justify-content: center;
display: flex;
align-items: center;
width: 100%;
}

.footer-container a {
padding: 0px 16px;
text-decoration: none;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
font-size: medium;
}

.fa:hover {
color: #45405F;
}

.footer-icons {
display: flex;
justify-content: center;
gap:20px;
padding-bottom: 10px;
}

.copyright {
color:#f2f2f2;
overflow: hidden;
margin-bottom: -30px;
}

.telegram{
padding: 0px;
width: 30px;
text-decoration: none;
}

.telegram:hover{
opacity: 0.7;
}

.linkedin{
padding: 0px;
width: 30px;
text-decoration: none;
}

.linkedin:hover{
opacity: 0.7;
}

.insta{
padding: 0px;
width: 30px;
text-decoration: none;
}

.insta:hover{
opacity: 0.7;
}

This is my Javascript code:

const header = document.querySelector('.header');

window.addEventListener("scroll", () => {
if(window.scrollY >= 150){
    header.classList.add("scrolled");
} else if(window.scrollY <=100) {
    header.classList.remove("scrolled");
}
});

//Hamburger Toggle for mobile 
const menuIcon = document.getElementById('menu-icon');
const navMenu = document.getElementById('navMenu');

menuIcon.addEventListener('click', () => {
navMenu.classList.toggle('show');
});

window.addEventListener('load', function(){
this.document.querySelector('.arrow-wrap').computedStyleMap.display = 'block';
});

// Select all cards
const cards = document.querySelectorAll('.card');

// Add event listeners to each card
cards.forEach(card => {
const cardInner = card.querySelector('.card-inner');

// Only flip when you click the card front
const cardFront = card.querySelector('.card-front');
cardFront.addEventListener('click', function (e) {
    e.stopPropagation(); // Prevent the event from propagating to the document
    cardInner.classList.toggle('flip'); // Flip the card
    card.classList.toggle('expand'); // Expand the card
});

// Close button logic (for collapsing and un-flipping)
const closeButton = card.querySelector('.close-btn');
closeButton.addEventListener('click', function (e) {
    e.stopPropagation(); // Prevent clicking the card behind the button
    cardInner.classList.remove('flip'); // Remove the flip effect
    card.classList.remove('expand'); // Collapse the card
});
});



const nextButtons = document.querySelectorAll('.nextBtn');
const backButtons = document.querySelectorAll('.backBtn');
const galleries = document.querySelectorAll('.gallery');

// Function to scroll the gallery
function scrollGallery(direction, gallery) {
const scrollAmount = gallery.clientWidth;
gallery.scrollBy({ left: direction * scrollAmount, behavior: 'smooth' });
}

// Adding event listeners to each pair of buttons
nextButtons.forEach((btn, index) => {
btn.addEventListener('click', () => scrollGallery(1, galleries[index]));
});

backButtons.forEach((btn, index) => {
btn.addEventListener('click', () => scrollGallery(-1, galleries[index]));
});


window.addEventListener('scroll', function() {
const footer = document.querySelector('.footer');
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
const scrolled = window.scrollY;

if (Math.ceil(scrolled) >= scrollable) {
    footer.classList.add('expanded'); // Expand footer when at the bottom
} else {
    footer.classList.remove('expanded'); // Hide footer when not at the bottom
}
});