Custom menu able to import data from a CSV file with semicolons separators [duplicate]

I would like to have a script for downloading into a sheet the values contained on a CSV file (stored on my laptop) and which using as separators semicolons.

Into Google Sheets, I would like to have a customized menu which can allow the followings things :

  • Displaying a popup window in order to select my CSV file stored somewhere into my laptop.
  • After, the script needs to get back the values contained into the selected CSV file.
  • At the end, I would like to have the values pasted into my current sheet and if possible, that the popup window be closed.

On a previous post, I found this code :

Google App Scripts side :

function onOpen() {
  SpreadsheetApp.getUi().createMenu("Import DI GMAO").addItem("Choisir un fichier CSV sur mon ordinateur ...", "importCsv").addToUi();

}

function importCsv(e){
  if (!e) {
    SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutputFromFile("index"), "Téléchargement d'un fichier DI GMAO");
    return;
  }
  const csv = Utilities.parseCsv(Utilities.newBlob(...e).getDataAsString());
    
  //Browser.msgBox(csv);
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange(1, 1, csv.length, csv[0].length).setValues(csv);
}

HTML side :

<form>
  <input type="file" name="file" onchange="importCsv(this.parentNode)" accept=".csv,text/csv">
  <div id="progress">Attente ...</div>
</form>
<script>
function importCsv(e) {
  const div = document.getElementById("progress");
  div.innerHTML = "Téléchargement en cours ...";
  const file = e.file.files[0];
  const f = new FileReader();
  f.onload = d => google.script.run.withSuccessHandler(_ => {
    div.innerHTML = "Téléchargement terminé !";
    setTimeout(google.script.host.close, 1000);
  }).importCsv([[...new Int8Array(d.target.result)], file.type, file.name]);
  f.readAsArrayBuffer(file);
}
</script>

This code works perfectly only if my CSV file have as separators commas (,).
If the CSV file have as separators semicolons (;), and that’s my case, the script doesn’t works and I didn’t understand why.

Google Apps Script – Custom menu able to import data from a CSV file with semicolons separators

I would like to have a script for downloading into a sheet the values contained on a CSV file (stored on my laptop) and which using as separators semicolons.

Into Google Sheets, I would like to have a customized menu which can allow the followings things :

  • Displaying a popup window in order to select my CSV file stored somewhere into my laptop.
  • After, the script needs to get back the values contained into the selected CSV file.
  • At the end, I would like to have the values pasted into my current sheet and if possible, that the popup window be closed.

On a previous post, I found this code :

Google App Scripts side :

function onOpen() {
  SpreadsheetApp.getUi().createMenu("Import DI GMAO").addItem("Choisir un fichier CSV sur mon ordinateur ...", "importCsv").addToUi();

}

function importCsv(e){
  if (!e) {
    SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutputFromFile("index"), "Téléchargement d'un fichier DI GMAO");
    return;
  }
  const csv = Utilities.parseCsv(Utilities.newBlob(...e).getDataAsString());
    
  //Browser.msgBox(csv);
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange(1, 1, csv.length, csv[0].length).setValues(csv);
}

HTML side :

<form>
  <input type="file" name="file" onchange="importCsv(this.parentNode)" accept=".csv,text/csv">
  <div id="progress">Attente ...</div>
</form>
<script>
function importCsv(e) {
  const div = document.getElementById("progress");
  div.innerHTML = "Téléchargement en cours ...";
  const file = e.file.files[0];
  const f = new FileReader();
  f.onload = d => google.script.run.withSuccessHandler(_ => {
    div.innerHTML = "Téléchargement terminé !";
    setTimeout(google.script.host.close, 1000);
  }).importCsv([[...new Int8Array(d.target.result)], file.type, file.name]);
  f.readAsArrayBuffer(file);
}
</script>

This code works perfectly only if my CSV file have as separators commas (,).
If the CSV file have as separators semicolons (;), and that’s my case, the script doesn’t works and I didn’t understand why.

Does anyone have any idea? Thank you in advance for your help.

django form submit is not sending all fields in the form when the fields are populated through javascript

When i fill out the form manually, it posts all 7 fields correctly. However, if the form is auto populated through js, the post request is only sending 2 out of the 7 fields (previous_package_description and comments). The script seems to be populating the fields correctly on the form, but they are just not being sent. Any help would be appreciated, thanks in advance

package.html

<form action="{% url 'add_supplier_package' supplier_id=supplier_id supplier_ingredient_supplypoint_id=supplier_ingredient_supplypoint.pk %}" method="POST" class="form" enctype="multipart/form-data">
                {% csrf_token %}
        
                <!-- Group 1: Previous Package Description -->
                <fieldset id="group-1">
                    <legend>Previous Package Description</legend>
                    <div class="form-row">
                        {{ form.previous_package_description.label_tag }}
                        {{ form.previous_package_description }}
                    </div>
                </fieldset>
        
                <!-- Group 2: Package Details -->
                <fieldset id="package-details-group">
                    <legend>Add New Packsize</legend>
        
                    <div class="form-row">
                        {% for field in form %}
                            {% if field.name != "package_sizes" and field.name != "supplier_ingredient_supplypoint" and field.name != "package_description" and field.name != "previous_package_description" %}
                                <div class="form-item">
                                    {{ field.label_tag }}
                                    {{ field }}
                                </div>
                            {% endif %}
                        {% endfor %}
                    </div>
        
                    <!-- Package Sizes Section -->
                    <div class="form-row">
                        <label for="package_sizes">Package Sizes:</label>
                        <div id="package_sizes_list">
                            <!-- Dynamic package size inputs will appear here -->
                        </div>
                        <button type="button" id="addPackageSizeButton" style="width: 20%;"class="btn" onclick="addPackageSize()">Add Package Size</button>
                    </div>
        
                    <!-- Auto-filled Package Description -->
                    <div class="form-row">
                        <label for="package_description">Package Description:</label>
                        <input type="text" id="package_description" name="package_description" readonly>
                    </div>
        
                    <!-- Hidden field to store package sizes -->
                    {{ form.package_sizes }}

                    <input type="hidden" name="supplier_ingredient_supplypoint" value="{{ supplier_ingredient_supplypoint.supplier_ingredient_supplypoint_id }}">
                </fieldset>
        
                <!-- Submit and Cancel Buttons -->
                <div class="form-button">
                    <button type="submit" class="btn" onclick="return confirm('Confirm Submit?')"><span>Submit</span></button>
                    <button type="button" class="btn cancel" onclick="history.back()"><span>Close</span></button>
                </div>
            </form>

form.py

class SupplierPackageForm(forms.ModelForm):
    previous_package_description = forms.ModelChoiceField(
        queryset=PackageHeader.objects.all(),  
        label="Previous Package Description",
        required=False,  
        empty_label="-- Select Existing Packsize --",
    )
    package_description = forms.CharField(
        max_length=200,
        label="Package Description (auto-filled)",
        required=False,
        widget=forms.TextInput(attrs={'readonly': 'readonly'})
    )
    package_type = forms.ChoiceField(
        choices=[
            (None, "-- None --"),
            ("IBC", "IBC"),
            ("PK", "Prepack"),
            ("DRUM", "DRUM"),  
            ("PAIL","PAIL"),
            ("BULK","BULK")
        ],
        label="Package Type",
        required=False,
        widget=forms.Select(attrs={"placeholder": "Select Package Type"})
    )
    uom = forms.ModelChoiceField(
        queryset=PackageUOM.objects.all(),
        label="Unit of Measurement",
        required=True,
        to_field_name='uom',
        empty_label="-- Select UOM --",
    )
    package_sizes = forms.CharField(
        widget=forms.HiddenInput(),
        required=False
    )
    supplier_ingredient_supplypoint = forms.ModelChoiceField(
        queryset=SupplierIngredientSupplyPoint.objects.all(),
        required=True,
        widget=forms.HiddenInput()
    )
    comments = forms.CharField(
        max_length=200,
        label="Comments",
        required=False,
        widget=forms.Textarea(attrs={"placeholder": "Enter comments here", "rows": 3, "cols": 40})
    )

    class Meta:
        model = SupplierPackage  # Connect the form to the SupplierPackage model
        fields = ['previous_package_description', 'package_description', 'package_type', 'uom','package_sizes', 'supplier_ingredient_supplypoint', 'comments']

    def __init__(self, *args, **kwargs):
        supplier_ingredient_supplypoint = kwargs.pop('supplier_ingredient_supplypoint', None)
        super().__init__(*args, **kwargs)

        if supplier_ingredient_supplypoint:
            self.initial['supplier_ingredient_supplypoint'] = supplier_ingredient_supplypoint
            self.fields['supplier_ingredient_supplypoint'].queryset = SupplierIngredientSupplyPoint.objects.filter(
                pk=supplier_ingredient_supplypoint.pk
            )

        self.fields['previous_package_description'].queryset = PackageHeader.objects.all()
        self.fields['previous_package_description'].choices = [("", "-- Add New Packsize --")] + [
            (package.package_id, f"{package.package_description} ({package.comments or ''})")
            for package in PackageHeader.objects.all()
        ]
        self.initial['previous_package_description'] = ""

js function

document.addEventListener('DOMContentLoaded', function () {
                const previousDescriptionField = document.querySelector('[name="previous_package_description"]');
                const packageDetailsGroup = document.getElementById('package-details-group');
                const packageDescriptionField = document.getElementById('package_description');
                const uomField = document.getElementById('id_uom');
                const packageTypeField = document.getElementById('id_package_type');
                const packageSizesList = document.getElementById('package_sizes_list');

                function toggleGroupState() {
                    if (previousDescriptionField.value) {
                        packageDetailsGroup.style.backgroundColor = '#e0e0e0';
                        packageDetailsGroup.querySelectorAll('input, select, button').forEach(input => {
                            input.setAttribute('readonly', true);
                            input.setAttribute('disabled', true);
                        });

                        // Fetch data and populate fields
                        fetch(`${getPackageDetailsUrl}?package_id=${previousDescriptionField.value}`)
                            .then(response => response.json())
                            .then(data => {
                                console.log('Returned data:', data);
                                if (!data.error) {
                                    uomField.value = data.uom;
                                    packageTypeField.value = data.package_type;

                                    packageDescriptionField.value = data.package_description;

                                    // Populate the comments field
                                    const commentsField = document.getElementById("id_comments");
                                    if (commentsField) {
                                        commentsField.value = data.comments || "";  // Ensure it's not null
                                    }

                                    // Clear existing package sizes and add new ones
                                    packageSizesList.innerHTML = '';

                                    if ( !!data.package_sizes ) {
                                        data.package_sizes.split(',').forEach(size => {
                                            const sizeInput = document.createElement('input');
                                            sizeInput.type = 'text';
                                            sizeInput.value = size.trim();
                                            sizeInput.setAttribute('readonly', true);
                                            sizeInput.classList.add('package-size-input');
                                            packageSizesList.appendChild(sizeInput);
                                        });
                                    }
                                }
                            })
                            .catch(error => {
                                console.error('Error fetching package details:', error);
                            });
                    } else {
                        packageDetailsGroup.style.backgroundColor = '';
                        packageDetailsGroup.querySelectorAll('input, select, button').forEach(input => {
                            input.removeAttribute('readonly');
                            input.removeAttribute('disabled');
                        });

                        packageDescriptionField.value = '';
                        packageSizesList.innerHTML = '';
                    }
                }

                previousDescriptionField.addEventListener('change', toggleGroupState);
                $('#id_previous_package_description').on('select2:select', toggleGroupState);
            });

Fastest way to process audio segments and concatenate buffers in Node.js

I am trying to optimize the performance of a Node.js function that generates audio segments (for example something like OpenAIs TTS API) and then concatenates the resulting audio buffers. My goal is to speed up the reading of each audio response into the buffer and the final concatenation of audio buffers.

Current Approach

Naively I thought that it would be as simple as calling all of the audio segments, then reading them all into their own buffer and putting them together. Here is a simplified version of what I am doing now:

const createAudioSegment = async ([i, segment]) => {
    const response = await openai.audio.speech.create({
        model: "tts-1",
        voice: "echo",
        input: text,
    });
    return response;
};

const audio_texts = ["text 1", "text 2"] // list of text to turn into audio

// Process dialogue segments in parallel
const audioSegments = await Promise.all(
    audio_texts.map((text) => createAudioSegment(text))
);


const audioBuffers = await Promise.all(
    audioSegments.map(async (segment) => {
        const arrayBuffer = await segment.arrayBuffer();
        return Buffer.from(arrayBuffer);
    })
);

const finalBuffer = Buffer.concat(audioBuffers);

Performance Issues

Overall, the time it takes to do this is usually 40-60 seconds. However, when logging the individual operations, I noticed that it is really the reading of each audio segment into its individual buffer that takes the majority of the time. As an example, for a scenario with 12 audio segments, I would expect to see the following timing:

  • Total Audio Segment Time: 2333 ms
  • Audio Buffer Total Read Time: 27455 ms
  • Audio Buffer Individual Read Times (ms): [1035,3420,6497,96,150,360,70,88,20344,32,83,254]
  • Buffer Concatenation Time: 2 ms

Question

What could be causing such a large discrepancy between the individual read times? Is this something that is avoidable with a more efficient way to do this?

Form disable the overflow

I try to implement an overflow in Form react-router, that’s work in a classic <div></div> but when I use <Form></Form> my overflow` stop to work. I don’t find any topic who talk about that.

The context is a Remix app who use import { Form } from 'react-router' the version of React route is the V7`

example work

<div>
 <div style={{overflowY: "auto"}}>
   <div>Truc</div>
   <div>Truc</div>
   .../...
   <div>Truc</div>
 </div>
</div>

example don’t work

<Form>
 <div style={{overflowY: "auto"}}>
   <div>Truc</div>
   <div>Truc</div>
   .../...
   <div>Truc</div>
 </div>
</Form>

is it a Bug or Formcannot work with the overflow or there is a trick for this case ? Because all the other style work except the overflow

Using Path Aliasing on NPM package

I am in the processes of developing an NPM package with many different directories. Internally, I manage this by using subpath imports in the package.json.

“imports” : { “#*”: “./src”, “#factories”: “./src/factories”…}

This works well when isolated to the package. However, when I install the package on a consuming application, the consuming application takes issue with the alaising when importing and using the package.

Is there a way to keep the path alaising isolated to the package and not have to transfer additional configuration to the consuming application, or do I need to just return to the uglier but functional unaliased relative paths?

Safari throwing alert when checking if an app Scheme/URL is valid

I am using the following code to check if a mobile app exists on the users phone, if it does then open app, if not then redirect to app store. It works clean on Android, but on Safari simply just checking if the Scheme/URL exists pops up a Safari cannot open the page because the address is invalid

  function checkReadyState() {
    if (reader.readyState === 4) {
      //check to see whether request for the file failed or succeeded
      if ((reader.status == 200) || (reader.status == 0)) {
        //page exists -- redirect to the url
        console.log(mobile+ " : does exist") ;
        document.location.href = mobile ;
      } else {
        //if the url does not exist
        console.log(mobile+ " : does NOT exist") ;
        goToStore() ;
      }
    }
    
  }// end of checkReadyState()
     
  console.log("Redirect to App or to Store") ;
  var mobile = "myapp://path/to/resource" ; 
  var reader = new XMLHttpRequest();
  reader.open('get', mobile, true);
                
  //check each time the ready state changes
  //to see if the object is ready
  reader.onreadystatechange = checkReadyState;
    
  // Sends the request for the file data to the server
  // Use null for "get" mode
  reader.send(null);    

I added all this because simply doing a window.location = mobile triggered the same Alert message. I thought this would do things behind the scene and not alert the user interrupting the UI flow.

How can I fix this or what other method can I use to simply check if an app/scheme exists without triggering an alert on the users phone?

How to properly handle errors in Nest.js service layer

We are building an API using Nest.js and MikroORM and we are having a debate on several things related to the service “layer” of Nest.js.

Let’s suppose you have the following update method on a service.

This method does several things:

  • Firsts, asks to the ORM if the project exists. If thats not the case it returns a NotFoundError

  • Second, it checks if the client exists. If that’s not the case, the service returns a NotFoundError.

  • Finally, proceeds with the update

async update(
  id: number,
  updateProjectDto: UpdateProjectDto,
): Promise<Projects> {
  try {
    const project = await this.projectRepository.findOneOrFail(id);
    if (updateProjectDto.client_id) {
      project.client = await this.clientService.findOne(
        updateProjectDto.client_id,
      );
    }

    this.projectRepository.assign(project, updateProjectDto);
    await this.projectRepository.getEntityManager().flush();
    return project;
  } catch (error) {
    this.logger.error('Error updating project', error);
    throw error;
  }
}

Here’s our findOne in clients

async findOne(id: number) {
  try {
    return await this.clientsRepository.findOneOrFail({ id });
  } catch (error) {
    this.logger.error(`Error finding client`, error);
    throw error;
  }
}

Our questions are the following:

  • When should we wrap our business logic inside a try catch?

  • Should we use try catch for every method on our API or let the errors bubble up, as we are not doing anything in particular with them?

  • Should the service throw HTTPExceptions (taking into account its not the “proper” layer to do that). We think it’s ok to throw them here for simplicity but who knows.

Thanks in advance!

Performance implications of using complex objects as default parameter

I want to use a very complicated object as a default parameter. For example, in prisma ORM, you can wrap multiple db calls in a transaction:

this.prisma.$transaction(async (tx) => {
  await tx.table1.create()
  await tx.table2.create()
}

These inner db calls can be complicated, so I may want helper functions for them. However, the helper functions can be called from many places and may or may not be used inside a transaction. To solve this, I optionally pass the transaction, and use it if it exists:

// My function with a complex default param
async createModelIfNotExists(name, color, prisma = this.prisma) {
  return await prisma.upsert({...})
}

...

// Call from within transaction, and use transaction's prisma client:
this.prisma.$transaction(async (tx) => {
  this.createModelIfNotExists("new model 1", "blue", tx)
  ...
})

// Call on its own, and it will use the prisma object attached to "this"
this.createModelIfNotExists("new model 2", "green")

Note that tx is a very large & complex object. It manages the db connection and keeps track of all my models.

My question is – is there a performance overhead to doing this? If I was writing Python, there would be, because Python tries to be smart & initializes the default parameter even if you don’t use the function. If I wrote it like Python, the function signature would look like this:

// The default param is now instantiated in the function
async createModelIfNotExists(name, color, prisma = null) {
  prisma = prisma ?? this.prisma
  return await prisma.upsert({...})
}

I am concerned about the potential overhead of instantiating this object even when it’s not used.

I tried Googling this, but have only seen results for more basic JS objects that the programmer writes themselves.

Alternatively, if you have suggestions on how to test the performance of this, I could do that instead.

Google provider no response after user login

I have a simple snippet involving Firebase Authentication with two options: email/pass and google.
My problem is that users can use the option email/pass smoothly.
Regarding Google provider, it can redirect to Google’s Oauth2 page, where users select and log in with their Google account. It also redirects back to my original page. However, it seems that the successful callback and error callback have never fired. (Note: with user/pass those callbacks fire as expected)

Here is what I tried

  1. Whitelist domain -> done
  2. Enable Google Provider in Firebase’s console -> done

Are there any tips to debug this issue?

window.addEventListener('load', function () {
    document.getElementById('sign-out').onclick = function () {
      firebase.auth().signOut();
    };
  
    // FirebaseUI config.
    var uiConfig = {
      signInSuccessUrl: '/',
      signInOptions: [
        firebase.auth.GoogleAuthProvider.PROVIDER_ID,
        firebase.auth.EmailAuthProvider.PROVIDER_ID
      ],
    };
  
    firebase.auth().onAuthStateChanged(function (user) {
      if (user) {
        // if user is signed in, handle business logic here
      } else {
        // User is signed out.
        // Initialize the FirebaseUI Widget using Firebase.
        var ui = new firebaseui.auth.AuthUI(firebase.auth());
        // Show the Firebase login button.
        ui.start('#firebaseui-auth-container', uiConfig);
      }
    }, function (error) {
      console.error("Authentication state change error:", error);
    });
  });

Copy and paste in the draggable object

I have html script like this,

<div style={{width:"200px",height:"100px"}} draggable={true}>
<div style={{width:"100px",height:"50px"}}> copy test</span>
</div>

This div is draggable, then I want to copy the text,

However I tried to copy the text, the div is dragged.

Is there any good method for this?

Change hover color of an input type=”range”

I have a react component named DocumentView that has a range slider to show the zoom level of a document. I tried to change the color of the input range on hovering with Tailwind CSS, but it shows the browser’s default color.

const DocumentView = ({ data }) => {
  const [scale, setScale] = useState(1);

  return (
    <div className="flex items-center w-32">
      <input
        type="range"
        min="0.3"
        max="1.5"
        step="0.1"
        value={scale}
        onChange={zoomLevel}
        aria-label="Zoom Level"
        className="w-full h-2 accent-[#7357fd] bg-transparent rounded-lg hover:accent-[#694cfdce] cursor-pointer"
        />
    </div>
  );
};

I need help figuring out how to display the color of the input range when hovering over the filled portion. I tried to find a solution with the help of AI, but I couldn’t get a proper answer because the custom CSS solutions provided did not work at all.

Why is my CO2 threshold check failing when the value is slightly over the limit (floating-point issue)

I’m building a CO2 savings tracker for a hospitality site, where users save CO2 and can plant a tree when their total savings reach 100kg. However, I’m encountering an issue where, when the CO2 value is just over 100kg, the “Plant a Tree” button does not get enabled.

I suspect this is a floating-point precision problem, as the CO2 value seems to be slightly less than 100 when displayed, even though it’s technically above the threshold. Below is the code for the tracker:

class GreenHospitality {
    constructor() {
        this.co2Saved = 0;
        this.treeThreshold = 100.00; // Threshold to plant a tree
    }

    updateCO2() {
        setTimeout(() => {
            const newCO2 = Math.random() * 5 + 0.01; // Small random CO2 increase
            this.co2Saved += newCO2;
            console.log(this.co2Saved.toFixed(2));

            if (this.co2Saved >= this.treeThreshold) {
                console.log("You can plant a tree!");
            }
        }, 3000);
    }
}

This is for enabling the button:

<!-- Plant Tree Button -->
<button id="plant-tree-btn" disabled>Plant a Tree</button>

<!-- Upgrade Tree Button -->
<button id="upgrade-tree-btn" disabled>Upgrade Tree</button>

if (this.co2Saved >= this.treeThreshold) {
    this.treeStatus.textContent = "You can now plant a tree!";
    this.plantTreeBtn.disabled = false;
} else {
    this.treeStatus.textContent = "You need more CO₂ to plant a tree!";
    this.plantTreeBtn.disabled = true;
}

Button Event Listeners:

document.getElementById("plant-tree-btn").addEventListener("click", () => game.plantTree());
document.getElementById("upgrade-tree-btn").addEventListener("click", () => game.upgradeTree());

Even though the CO₂ savings show as slightly above 100kg (like 100.001), the button to plant a tree does not get enabled. It seems like there’s a tiny difference in value due to floating-point precision errors.

I’ve tried rounding the value and using .toFixed(2) for display, but it still doesn’t enable the button at the correct moment.

Has anyone encountered this issue? Any suggestions on how to fix the threshold check in a way that accounts for small floating-point precision errors?

What I’ve Tried:

  • Using .toFixed(2) for display

  • Rounding the number manually before the comparison

  • Using Math.floor() and Math.ceil() to adjust the value

Encountering this issue “ERR_INVALID_FILE_URL_PATH: File URL path must be absolute” while running test suite

I am trying to set up Webpack locally and try to run the test,

yarn test

but it failed I don’t know how to fix it. I am trying to set up Webpack locally and run its test suite, but I am encountering an error related to “ERR_INVALID_FILE_URL_PATH: File URL path must be absolute” during schema precompilation.

yarn run v1.22.22
$ yarn lint
$ yarn setup
$ node ./setup/setup.js
$ yarn code-lint && yarn special-lint && yarn type-lint && yarn typings-test && yarn module-typings-test && yarn yarn-lint && yarn pretty-lint && yarn spellcheck
$ node node_modules/eslint/bin/eslint.js --cache .
(node:8860) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
$ node node_modules/tooling/lockfile-lint && node node_modules/tooling/schemas-lint && node node_modules/tooling/inherit-types && node node_modules/tooling/format-schemas && node tooling/generate-runtime-code.js && node tooling/generate-wasm-code.js && node node_modules/tooling/format-file-header && node node_modules/tooling/compile-to-definitions && node node_modules/tooling/precompile-schemas && node node_modules/tooling/generate-types --no-template-literals
node:internal/url:1433
    throw new ERR_INVALID_FILE_URL_PATH('must be absolute');
          ^

TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must be absolute
during precompilation of D:/GSOC/webpack/schemas/plugins/asset/AssetGeneratorOptions.json
    at getPathFromURLWin32 (node:internal/url:1433:11)
    at fileURLToPath (node:internal/url:1464:35)
    at loadSchema (D:GSOCwebpacknode_modulestoolingprecompile-schemasindex.js:21:16)
    at Ajv._loadSchema (D:GSOCwebpacknode_modulestoolingnode_modulesajvdistcore.js:207:52)
    at Ajv.loadMissingSchema (D:GSOCwebpacknode_modulestoolingnode_modulesajvdistcore.js:196:47)
    at Ajv._compileAsync (D:GSOCwebpacknode_modulestoolingnode_modulesajvdistcore.js:186:41)
    at Ajv.runCompileAsync (D:GSOCwebpacknode_modulestoolingnode_modulesajvdistcore.js:171:50)
    at async precompileSchema (D:GSOCwebpacknode_modulestoolingprecompile-schemasindex.js:211:20) {
  code: 'ERR_INVALID_FILE_URL_PATH'
}

Node.js v20.15.0
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Can someone help me set up Webpack locally or try to fix this problem?

I am trying to set up the webpack locally.

Saving a reservation button [closed]

I have a problem with saving the data of the person who clicked and the function counting down the reservation time after clicking the button. I am completely stuck, does anyone of you know how I can solve this and where the problem lies, after pressing the button changes to reserved with a countdown time, but after refreshing the page no data is saved. so that if any user enters, they can also click this button, and it should work so that when one person clicks, save who clicked, counts down the reservation time 48h back, thus blocking the possibility of pressing the button for other users and they only see how much time is reserved and after that time the button should return to the possibility of re-booking.

Please help.

AJAX:

function handle_reservation() {
    $user_id = get_current_user_id();
    $post_id = intval($_POST['post_id']);

    if (!$user_id) {
        wp_send_json_error(['message' => 'Musisz być zalogowany, aby rezerwować.']);
    }

    $current_reservation = get_post_meta($post_id, '_reserved_by', true);
    $reserved_until = get_post_meta($post_id, '_reserved_until', true);

    if ($current_reservation && time() < $reserved_until) {
        wp_send_json_error([
            'message' => 'Post już zarezerwowany do ' . date('Y-m-d H:i:s', $reserved_until),
            'reserved_by' => get_userdata($current_reservation)->user_login
        ]);
    }

    update_post_meta($post_id, '_reserved_by', $user_id);
    update_post_meta($post_id, '_reserved_until', time() + 48 * 60 * 60);

    wp_send_json_success([
        'message' => 'Post zarezerwowany.',
        'reserved_by' => get_userdata($user_id)->user_login
    ]);
}
add_action('wp_ajax_reserve_post', 'handle_reservation');

function check_reservation_status() {
    $post_id = intval($_POST['post_id']);
    $reservation = get_post_meta($post_id, '_reserved_by', true);
    $reserved_until = get_post_meta($post_id, '_reserved_until', true);

    if ($reservation && time() < $reserved_until) {
        wp_send_json_success([
            'reserved' => true,
            'reserved_by' => get_userdata($reservation)->user_login,
            'time_left' => $reserved_until - time()
        ]);
    } else {
        wp_send_json_success(['reserved' => false]);
    }
}
add_action('wp_ajax_check_reservation_status', 'check_reservation_status');

function enqueue_reserve_post_script() {
    wp_enqueue_script('reserve-post-js', get_template_directory_uri() . '/js/reserve-post.js', ['jquery'], null, true);
    
    wp_localize_script('reserve-post-js', 'wp_vars', [
        'ajax_url' => admin_url('admin-ajax.php'),
        'user_id' => get_current_user_id()
    ]);
}
add_action('wp_enqueue_scripts', 'enqueue_reserve_post_script');

JS:

document.addEventListener('DOMContentLoaded', function() {
    const buttons = document.querySelectorAll('.reserve-button');

    buttons.forEach(function(button) {
        button.style.backgroundColor = "green";
        button.style.color = "white";
        button.style.border = "none";
        button.style.padding = "10px 20px";
        button.style.fontSize = "16px";
        button.textContent = "Zarezerwuj";

        const postId = button.getAttribute('data-post-id');
        const userId = wp_vars.user_id;
        const reservationInfo = button.nextElementSibling;
        const reservedByElement = reservationInfo.querySelector('.reserved-by');

        checkReservation(postId, button, reservationInfo, reservedByElement);

        button.addEventListener('click', function() {
            reservePost(postId, userId, button, reservationInfo, reservedByElement);
        });

        button.addEventListener('mouseenter', function() {
            if (!button.disabled) {
                button.style.backgroundColor = "white";
                button.style.color = "orange";
                button.style.border = "2px solid orange";
                button.textContent = "ZAREZERWUJ";
            }
        });

        button.addEventListener('mouseleave', function() {
            if (!button.disabled) {
                button.style.backgroundColor = "green";
                button.style.color = "white";
                button.style.border = "none";
                button.textContent = "Zarezerwuj";
            }
        });
    });
});

function checkReservation(postId, button, reservationInfo, reservedByElement) {
    jQuery.ajax({
        url: wp_vars.ajax_url,
        type: 'POST',
        data: {
            action: 'check_reservation_status',
            post_id: postId
        },
        success: function(response) {
            if (response.success && response.data.reserved) {
                const { time_left, reserved_by } = response.data;
                button.textContent = `Zarezerwowane na ${formatTime(time_left)}`;
                button.style.backgroundColor = "orange";
                button.style.color = "white";
                button.disabled = true;
                startCountdown(button, time_left);

                reservedByElement.textContent = reserved_by;
                reservationInfo.style.display = "block";
            }
        },
        error: function() {
            console.error('Błąd podczas sprawdzania rezerwacji.');
        }
    });
}

function reservePost(postId, userId, button, reservationInfo, reservedByElement) {
    jQuery.ajax({
        url: wp_vars.ajax_url,
        type: 'POST',
        data: {
            action: 'reserve_post',
            post_id: postId,
            user_id: userId
        },
        success: function(response) {
            if (response.success) {
                const time_left = 48 * 60 * 60;
                button.textContent = `Zarezerwowane na ${formatTime(time_left)}`;
                button.style.backgroundColor = "orange";
                button.style.color = "white";
                button.disabled = true;
                startCountdown(button, time_left);

                reservedByElement.textContent = response.data.reserved_by;
                reservationInfo.style.display = "block";
            } else {
                alert('Nie udało się zarezerwować: ' + response.data.message);
            }
        },
        error: function() {
            alert('Błąd podczas rezerwacji.');
        }
    });
}

function formatTime(seconds) {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    return `${hours}h ${pad(minutes)}m`;
}

function pad(num) {
    return num < 10 ? '0' + num : num;
}

function startCountdown(button, remainingTime) {
    const countdownInterval = setInterval(() => {
        remainingTime -= 1;
        if (remainingTime <= 0) {
            clearInterval(countdownInterval);
            button.textContent = "Zarezerwuj ponownie";
            button.style.backgroundColor = "green";
            button.style.color = "white";
            button.disabled = false;
        } else {
            button.textContent = `Zarezerwowane na ${formatTime(remainingTime)}`;
        }
    }, 1000);
}