How to deploy nextjs14 app on server with pm2 and apache

I built a nextjs14 app that’s essentially a to do list. It sends post and get requests to a mysql database to update the database and get data.

I want to deploy the app to a rhel server and serve it through apache through a virtual host and reverse proxy. I’ll use node to run the app and keep the app running using pm2 as the process manager.

My question is: what files do I need to transfer onto my server?
I ran npm run build and built everything into a .next directory. Do I just move the .next directory onto my server somewhere (such as /opt/node/app, where app is the name of my application) and run it using pm2? What would I even run? I read somewhere about a server api but i’m confused why’d I’d need an API.

Generating pdfs in next app dont work on deploy why?

I have a problem using jspdf in my next app. In local it works correctly but when I deploy my app in vercel the code below only prints the first doc.text . I don’t know why. Thanks for your help.

This is the code I tried.

import { jsPDF} from "jspdf";

function GeneratePDF (){
    const handlePDF = async () => {
        const doc =y new jsPDF("p", "pt", "a4", false);
        doc.text("hello world!", 10 ,10);
doc.text("this does not print in vercel", 10, 20);
        await doc.save("mypdf.pdf");
    }

    return (
        <button onClick={handlePDF}>Generate PDF</button>
    )
} 

How to close popup when redirect and use query parameter (JS)

I am building a webtool that should be able to call the Strava api. Before being able to create the actual request, the customer should give the authorisation. This is done via an authorise call:
https://www.strava.com/oauth/authorize?client_id=123456&response_type=code&redirect_uri=http://localhost/exchange_token&approval_prompt=force&scope=activity:read_all

It consists of a client_id which is linked to my application and a redirect url. When opening the url, the user sees a screen where he/she is able to authorise my app. After an approval, he/she got redirected to the redirect url with a query parameter called code=730f5fbb0b7djske9d66e85568a526e4e8sfb2ah. This is the actual authorisation code that should be used when doing new calls.

My question is how to:

  1. Open the authorise link in a popup
  2. Wait for the user to click on the approval button
  3. Close the popup when the client got redirected
  4. Use the code query parameter that was shown in the redirect url in the webtool to make new calls

I already found some javascript code to execute step one, but that’s all:

  const url = await 'https://www.strava.com/oauth/authorize?client_id=123456&response_type=code&redirect_uri=http://localhost/exchange_token&approval_prompt=force&scope=activity:read_all'; 
  const authPopup = window.open(url, "", "popup=true"); 

Step 2 should be done by the customer, but could someone help me with step 3 and 4? Any tips are welcome. I am quite new to javascript.

How can I change the children-parent relationship in bookmarks in Javascript? or delete the children levels

I am a simple office worker with basic programming knowledge who wants to make her work easier.
I need to delete all the bookmarks levels from a PDF.

I’m using PDF X-Change Editor and for this I’m using a Javascript console

Basically, I want- to change all the children bookmarks to the same level as the parents bookmarks

enter image description here

I have this code but I have only been able to get it to show if children bookmarks exist

// Get the root bookmark node of the document
var rootBookmark = this.bookmarkRoot;
 
// Check if the root bookmark node exists

if (rootBookmark) {
    // Iterate through each child bookmark

    for (var i = 0; i < rootBookmark.children.length; i++) {
        var bookmark = rootBookmark.children[i];
        // Perform operations on each bookmark, such as accessing its name or properties

        console.println("Bookmark Name: " + bookmark.name);
 
    // Check every children
        if (rootBookmark.children[i].children){
             console.println("Si entro");
 
        }else{
            console.println("no");
        }
 
    }
} else {
    console.println("No bookmarks found in the document.");
}
 

Transition doesn’t work on Dialog component from HeadlessUI

I added <Dialog> from HeadlessUI and set up TailwindCSS but when I try to open Modal window on the page there is no transition at all despite I provided everything from the example

CODE

Modal.tsx:

type TProps = {
   isOpened: boolean;
   onClose: VoidFunction;
   children?: ReactNode;
};

export const Modal = ({ isOpened, onClose, children }: TProps) => {
   return (
      <Transition show={isOpened} as={Fragment}>
         <Dialog as="div" className={s.modalWrapper} open={isOpened} onClose={onClose}>
            <Transition.Child
               as={Fragment}
               enter="ease-out duration-300"
               enterFrom="opacity-0"
               enterTo="opacity-100"
               leave="ease-in duration-200"
               leaveFrom="opacity-100"
               leaveTo="opacity-0"
            >
               <Dialog.Overlay className={s.backdrop} />
            </Transition.Child>

            <Transition.Child
               as={Fragment}
               enter="ease-out duration-300"
               enterFrom="opacity-0 scale-95"
               enterTo="opacity-100 scale-100"
               leave="ease-in duration-200"
               leaveFrom="opacity-100 scale-100"
               leaveTo="opacity-0 scale-95"
            >
               <Dialog.Panel className={s.modal}>{children}</Dialog.Panel>
            </Transition.Child>
         </Dialog>
      </Transition>
   );
};

and here is how I call it (if it matters):

AddProduct.tsx:

export const AddProductCard = () => {
   const [modalOpened, setModalOpened] = useState<boolean>(false);

   return (
      <>
         <div className={s.addProductCard} onClick={() => setModalOpened(true)}>
            <PlusIcon className={s.plusIcon} />
         </div>

         <AddProductModal
            modalOpened={modalOpened}
            onClose={() => setModalOpened(false)}
         />
      </>
   );
};

So I added <Transition> and <Transition.Child>

and here is tailwind.config.js:

/** @type {import('tailwindcss').Config} */
module.exports = {
   purge: ['./src/**/*.{js,ts,jsx,tsx}'],
   content: ['./src/**/*.{js,ts,jsx,tsx}'],
   theme: {
      extend: {},
   },
   variants: {
      extend: {},
   },
   plugins: [],
};

In addition I do have postcss, tailwindcss, and autoprefixer installed

Use static create method instead of constructor

In my project I would like to use TypeOrm with Dataclass as it greatly simplifies how I have to write my classes. My problem is that TypeOrm is using the constructor when fetching data from the database and although it can be skipped with the property entitySkipConstructor it would not use default values then. Let’s say I have an entity like this:

@Entity({ name: 'users' })
class User extends Data {
  @PrimaryColumn() id: string = uuidv4();

  @Column() firstName!: string;
  @Column() lastName!: string;
}

The dataclass library creates a static create method like this:

User.create({ firstName: "John", lastName: "Doe" });

Is there any way I can tell TypeOrm to use this static create function instead of the constructor?

Discount Code Mutation not Reflecting in Dawn Theme UI

I’m currently using a GraphQL mutation within the Shopify Theme to apply a discount code and automatically update the cart.json. While the cart.json is successfully updating with the applied discount, the Dawn theme’s UI is not reflecting the discounted price.

To achieve this functionality, I’ve created a custom input field where users can enter the discount code, along with a custom button to trigger the discount application process.

 const button = document.getElementById("applyDiscountBtn");
  const clearButton = document.getElementById("clearCartBtn");

  clearButton.addEventListener("click", function () {
      fetch(window.Shopify.routes.root + 'cart/clear.js', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      })
      .then(response => {
      return response.json();
      })
      .catch((error) => {
      console.error('Error:', error);
      });
    window.location.reload();
    console.log('Cart has been cleared');
    });
  
  button.addEventListener("click", async function () {
    applyDiscountCode();
    await updateCartDiscountCodes();
    clearCookie('discount_code');
    await fetch(window.Shopify.routes.root + 'cart/add.js', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
        body: {"sections": "main-cart-footer"}
      })
      .then(response => {
      return response.json();
      })
      .catch((error) => {
      console.error('Error:', error);
      });
    window.location.reload();
    console.log('Click Completed');
    
  });
   
     function setCookie(cookieName, cookieValue, expirationDays) {
      const date = new Date();
      date.setTime(date.getTime() + (expirationDays * 24 * 60 * 60 * 1000));
      const expires = "expires=" + date.toUTCString();
      document.cookie = cookieName + "=" + cookieValue + ";" + expires + ";path=/";
    }  
 
     function applyDiscountCode() {
      const discountCodeInput = document.getElementById("discountCode");
      const discountCode = discountCodeInput.value.trim();

      // Check if the discount code is not empty
      if (discountCode !== "") {
        // Store discount code in cookie
        setCookie("discount_code", discountCode, 1);
        console.log("Discount code applied successfully!");
      } else {
        console.log("Please enter a valid discount code.");
      }
    }
   
    function getCookie(cookieName) {
    const name = cookieName + "=";
    const decodedCookie = decodeURIComponent(document.cookie);
    const cookieArray = decodedCookie.split(';');
    for(let i = 0; i <cookieArray.length; i++) {
        let cookie = cookieArray[i];
        while (cookie.charAt(0) === ' ') {
            cookie = cookie.substring(1);
        }
        if (cookie.indexOf(name) === 0) {
            return cookie.substring(name.length, cookie.length);
        }
    }
    return "";
}
   
     function updateCartDiscountCodes() {
    try {
    const cartId = getCookie("cart"); // You need to implement this function to get the cartId from the cookie
    const discount_code = getCookie("discount_code");
    const discountCodes = [discount_code]; // Example discount codes
    const variables = {
      cartId: "gid://shopify/Cart/" + cartId,
      discountCodes: discountCodes
    };
    console.log(variables.cartId, variables.discountCodes);
    const mutation = `
      mutation cartDiscountCodesUpdate($cartId: ID!, $discountCodes: [String!]) {
        cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {
          cart {
            checkoutUrl
          }
          userErrors {
            field
            message
          }
        }
      }
    `;
    const response = fetch('/api/2024-04/graphql.json', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Shopify-Storefront-Access-Token': 'xxxx-xxxx-xxxx' // Add your authentication token here
      },
      body: JSON.stringify({
        query: mutation,
        variables: variables
      })
    });
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = response.json();
    console.log('Mutation Response:', data);
  } catch (error) {
    console.error('Mutation Error:', error);
    // Handle error
  }
    
}
   
    function clearCookie(cookieName) {
    document.cookie = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
    }

No connection to the administartion panel. Django, JS

I’m having trouble connecting my snake game points to the model registered in admin. Then I want to use them to create a ranking.I dont use a JS on a daily basis so i use chatGtp to generate js code. I more or less understand the JS code. Its my code:

@require_POST
def submit_score(request):

    data = json.loads(request.body)
    score = data.get('score')
    user = request.user if request.user.is_authenticated else None

    if user:
        player_username = user.username
        new_score = Score(player=user, point=score, player_username=player_username)
        new_score.save()

    return HttpResponse("Dobry wynik!")

class Score(models.Model):

    player = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True)
    point = models.IntegerField()
    player_username = models.CharField(max_length=30) # Stores the username

    def __str__(self):
        return f'{self.player_username} - {self.point}'

function submitScore(score) {
  // fetch to send score
  fetch('submit-score/', { // The URL to change to the correct endpoint in Django
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-CSRFToken': getCookie('csrftoken') // Required to Django to prevent CSRF attacks
    },
    body: JSON.stringify({
      score: score
    })
  })
  .then(response => {
    console.log(response);
    if (response.ok) {
      return response.json();
    }
    throw new Error('Nie udało się zapisywać wyniku.');
  })
  .then(data => console.log('Wynik został zapisany:', data))
  .catch((error) => console.error('Błąd:', error));
}

I call the JS function in restart game. The game on the website works as it should

How do I connect my upload document form to my document storage in Kaleido?

Backgroud

Currently I am trying to connect my upload document form to my Kaleido document storage. My goal is to be able to send a PDF to my document storage and then return the hash to the front end and display it.

At the moment I have created a very simple front end and I have written some JS to handle the post part of the document upload. When I test uploading a sample PDF to my form, I get the error message “Upload failed: Network response was not ok Internal Server Error”, so I know I am at least trying to contact the API in a way. The problem I seem to be running into is my authorization to get into the Kaleido document storage. When I follow the link to my document storage API endpoint, I am prompted with entering in my username and password but when I correctly put it in and press login it just keeps prompting me to enter my credentials.

Also I have put my credentials into the envvars of the server I am running this on(KALEIDO_USERNAME and KALEIDO_PASSWORD) and just simply put in my email and my password I used to sign up for Kaleido. I’m not too sure if I need to use my personal Admin API key for my Authorization.

HTML CODE

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Upload Form</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <form id="uploadForm" class="upload-form">
    <h2>Upload Form</h2>
    <input type="text" name="name" placeholder="Name">
    <input type="file" name="document">
    <button type="submit">Upload</button>
  </form>

  <script src="script.js"></script>
</body>
</html>

Event Listener Script

document.getElementById('uploadForm').addEventListener('submit', function(event) {
    event.preventDefault();
    const formData = new FormData(this);

    fetch('/upload', {
        method: 'POST',
        body: formData
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok ' + response.statusText);
        }
        return response.json();
    })
    .then(data => {
        console.log(data);
        //Success
        alert('File uploaded successfully!');
    })
    .catch(error => {
        console.error('Error:', error);
        //Fail 
        alert('Upload failed: ' + error.message);
    });
});

Server Code

const express = require('express');
const multer = require('multer'); 
const fetch = require('node-fetch');
const fs = require('fs');
require('dotenv').config();
const app = express();
app.use(express.static(__dirname));
const upload = multer({ dest: 'uploads/' }); // Files will be temporarily stored in 'uploads' folder

app.get('/', (req, res) => {
    res.sendFile('./main.html', { root: __dirname });
  });

app.post('/upload', upload.single('document'), async (req, res) => {
    const { originalname, path: tempPath } = req.file;
    const { name } = req.body;

    const auth = Buffer.from(`${process.env.KALEIDO_USERNAME}:${process.env.KALEIDO_PASSWORD}`).toString('base64');

    try {
        // Read the file from the temporary path
        const fileData = fs.readFileSync(tempPath);

        const kaleidoResponse = await fetch('MY_DOCUMENT_API_ENDPOINT_URL', {
            method: 'POST',
            headers: {
                'Authorization': `Basic ${auth}`, 
            },
            body: JSON.stringify({
                name: name, // Use the file name input from the form
                file: fileData, // Send the file data
            }),
        });

        // Remove the file from the temporary storage
        fs.unlinkSync(tempPath);

        if (!kaleidoResponse.ok) throw new Error(`Kaleido responded with status: ${kaleidoResponse.status}`);

        const kaleidoData = await kaleidoResponse.json();
        res.json(kaleidoData);
    } catch (error) {
        console.error('Upload failed:', error);
        res.status(500).json({ error: 'Internal Server Error' });
    }
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));

Any help would be greatly appreciated or any insight on how to improve or make this type of thing better fell free to recommend anything.

Designing a game for 4 players [closed]

I would like to know how to toggle between 4 opponents for a game. I was learning how to design a board and learnt to toggle between 2 players. This is done via modulus. The toggle is constantly increasing by one. For example when

toggle % 2 == 1

it is an odd number but when

toggle % 2 == 0

it’s an even number.

Then

toggle = toggle + 1

Is there something like that for four players? What constantly incrementing operation can be done to toggle between 4 different players?

I tried out

toggle= toggle + 1

If toggle == N
toggle = 0

But this isn’t an incrementing value like the original one.

Converting OBJ to 3DM: Validity Issues in Generated Files

I’m attempting to load and convert an OBJ file to 3DM format using the rhino3dm library. Here’s the relevant code snippet:

import rhino3dm from 'rhino3dm';
import * as fs from 'fs';
import * as THREE from 'three';
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';

const rhino = await rhino3dm();
console.log('Loaded rhino3dm.');

const fileContent = fs.readFileSync('public/models/test.obj').toString();

const loader = new OBJLoader();
const obj = loader.parse(fileContent);

let exportGeometry = null;
if (obj.children) {
    obj.children.forEach((mesh) => {
        if (!exportGeometry) {
            console.log('here');
            exportGeometry = mesh.geometry;
        } else {
            exportGeometry = THREE.BufferGeometryUtils.mergeBufferGeometries([exportGeometry, mesh.geometry], false);
        }
    });
}
const rhinoMesh = rhino.Mesh.createFromThreejsJSON({data: exportGeometry})

const doc = new rhino.File3dm()
doc.objects().add(rhinoMesh, null)

let opts = new rhino.File3dmWriteOptions()
opts.version = 6;
let buffer = doc.toByteArrayOptions(opts);
fs.writeFileSync('public/models/test.3dm', buffer);
console.log('3DM file saved successfully.');

The code successfully generates a 3DM file, but unfortunately, the resulting file is not valid. When re-uploaded to a 3D viewer, it fails to load properly. I’ve followed the example from the repository, but I’m encountering this issue.

Any insights on why the generated 3DM file isn’t valid, and how I can address this problem?

Coding a vanilla Javascript drag and drop instructions maze game as a beginner. Where to start and resources?

I’m working on a webgame which is designed to help young children understand the concept of sequencing. I’, building it using HTML, CSS and Javascript and will be including it in an educational website.
I want to display a maze grid to the user and have a character ‘lost’ in the maze. The user will drag and drop instructions from predefined possibilities like ‘turn left’, ‘go forward’ etc. to create an instruction list and then hit go. The character then follows the instructions and hopefully escapes the maze or the user is told they lost and try again. As a beginner in Javascript I’m finding this difficult!

Firstly is this doable for a Javascript beginner?
How would I go about achieving this?
Are there any tutorials or resources which would be helpful?

I started out working on creating a slider puzzle game as I thought some of the concepts would be transferable. I’ve also looked at sortable lists in JS.

JS Getting HTTP Data From HTTPS Page

Do you guys have any simple ways to get forced http data from an https page? I have a forced https page because I’m using the camera for QR scanning (which forces me to use https), and a forced http server (a simple web server app using winsock) that I need to send the QR code do. Do you have any simple ways around the http communication block? For example in the past I have just requested fake images in js to the http server because I only needed to send data one way. This new program I need to get a small amount back from the http server onto the https page. I figured there would be a simple way with a custom image http header or something.