Elevenlabs add voice API call issue in Expo/React Native – unable to send audio files to API

I am creating an Expo app for mobile that allows users to clone voices by uploading audio clips. I am trying to communicate with the Elevenlabs API by allowing the user to upload audio clips using the Expo DocumentPicker, then sending a POST request to the API with the required information. The API reference can be found here: https://elevenlabs.io/docs/api-reference/add-voice. When I call the API, I get a response saying that the format is incorrect, and I believe it is relating to how the audio files are being sent.

I have these 2 functions:

This function in the screen that I am calling the file picker from:

const handlePickAudio = async () => {
    const result = await DocumentPicker.getDocumentAsync({
      type: 'audio/*',
      copyToCacheDirectory: true,
    });
    if (result.assets && result.assets.length > 0) {
      // setIsUploading(true);

      const voiceID = await ElevenLabs.createVoice("Demo Voice", [result.assets[0]]);
      console.log("Resulting Voice ID:", voiceID);
      
      if (voiceID) {
        // router.push({
        //   pathname: "/onboarding/onboarding10",
        //   params: { voiceID: voiceID },
        // });
      }
      else {
        Alert.alert('Error', 'Failed to create voice');
      }
      setIsUploading(false);
    }
  }

and this function in my elevenlabs functions file:

export const createVoice = async (name: string, audioClips: DocumentPicker.DocumentPickerAsset[]) => {
    // set data/options to send to API
    const formData = new FormData();
    formData.append('name', name);
    formData.append('remove_background_noise', 'true');
    
    // append each file individually
    for (const clip of audioClips) {
        const response = await fetch(clip.uri);
        const blob = await response.blob();
        formData.append('files', blob, clip.name);
    }

    const options = {
        method: 'POST',
        headers: {
            'Content-Type': 'multipart/form-data',
            'xi-api-key': 'apikey',
        },
        body: formData
    };

    let voiceID = '';

    // send data to API
    const response = await fetch('https://api.elevenlabs.io/v1/voices/add', options);
    const json = await response.json();
    
    voiceID = json.voice_id;

    return voiceID;
  }

When I call the API, I am getting the response:

response {"detail":[{"loc":["body","files",0],"msg":"Expected UploadFile, received: <class 'str'>","type":"value_error"}]}

I have tried converting the files to blobs and sending them that way, and that did not seem to work either. I also got a successful response from using this curl request on my desktop terminal:

curl --request POST 
  --url https://api.elevenlabs.io/v1/voices/add 
  --header 'Content-Type: multipart/form-data' 
  --header 'xi-api-key: apikey' 
  --form files=@/Users/myname/Desktop/sampleaudioclip.mp3 
  --form name=Samplename 
  --form remove_background_noise=true

It worked on my desktop, but when I try it in the mobile app in Expo, it seems to be giving the files in a different format that the API call does not accept. Please let me know if you would like any more information.

Javascript features in Unbuntu when activating credit/debit card fields and others fields using Stripe

I’m using stripe in a POS system that I’m developing for debit/credit card payment method. Thus, in my development environment (DE) which is running on Windows 11, the checkout payment is working perfectly. Now I’ve deployed the system to the Testing Environments (TE) which are running on Ubuntu 24 and Ubuntu 22, but I’m noticing that when I select “cash” as a payment method, in the DE the system shows the amount that need to be returned to customer.When I select “Credit/Debit” card as a payment method, the system shows fields that the customer needs to typpe the card information such card number, expiration date and CVV. However, in my TE none of this features are working.
Here are my codes:
Checkout View

class CheckoutView(View):
    @method_decorator(login_required)
    def get(self, request, order_id):
        """Handles GET requests to load the checkout page."""
        order = get_object_or_404(Order, id=order_id)

        if not order.items.exists():
            modal_message = "Cette commande ne contient aucun produit. Veuillez ajouter des produits ou contactez un manager pour supprimer la commande."
            return render(request, 'pos/orders/checkout.html', {
                'order': order,
                'modal_message': modal_message,
                'currency': None,
                'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
            })

        # Fetch active currency
        active_currency = Currency.objects.filter(is_active=True).first()
        if not active_currency:
            return render(request, 'pos/orders/checkout.html', {
                'order': order,
                'modal_message': 'Aucune devise active trouvée pour le magasin.',
                'currency': None,
                'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
            })

        return render(request, 'pos/orders/checkout.html', {
            'order': order,
            'currency': active_currency,
            'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
        })

    @method_decorator(login_required)
    def post(self, request, order_id):
        """Handles POST requests to process the checkout."""
        order = get_object_or_404(Order, id=order_id)

        # Ensure the order has items
        if not order.items.exists():
            modal_message = "Cette commande ne contient aucun produit. Le paiement ne peut pas être traité."
            return render(request, 'pos/orders/checkout.html', {
                'order': order,
                'modal_message': modal_message,
                'currency': None,
                'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
            })

        # Get active currency
        active_currency = Currency.objects.filter(is_active=True).first()
        if not active_currency:
            return render(request, 'pos/orders/checkout.html', {
                'order': order,
                'modal_message': 'Aucune devise active trouvée pour le magasin.',
                'currency': None,
                'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
            })

        # Get payment details
        payment_method = request.POST.get('payment_method')
        received_amount = request.POST.get('received_amount')
        discount_type = request.POST.get('discount_type')
        discount_amount = request.POST.get('discount_amount')

        # Validate received amount
        try:
            received_amount = Decimal(received_amount) if received_amount else None
        except (ValueError, InvalidOperation):
            return render(request, 'pos/orders/checkout.html', {
                'order': order,
                'modal_message': 'Montant reçu invalide.',
                'currency': active_currency,
                'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
            })

        # Apply discount if any
        try:
            if discount_type and discount_amount:
                discount_amount = Decimal(discount_amount)
                order.discount_type = discount_type
                order.discount_amount = discount_amount
                order.update_totals()  # Recalculate totals
            else:
                order.discount_type = None
                order.discount_amount = Decimal('0.00')
        except (ValueError, InvalidOperation):
            return render(request, 'pos/orders/checkout.html', {
                'order': order,
                'modal_message': 'Montant de remise invalide.',
                'currency': active_currency,
                'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
            })

        payment_amount = order.total_amount_with_tax
        change = None

        if payment_method == 'cash':
            # Cash payment logic
            if received_amount is None or received_amount < payment_amount:
                return render(request, 'pos/orders/checkout.html', {
                    'order': order,
                    'modal_message': 'Le montant reçu est inférieur au montant total.',
                    'currency': active_currency,
                    'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
                })
            change = received_amount - payment_amount
        else:
            # Non-cash payment logic
            payment_currency = 'USD'  # Assuming the payment gateway uses USD
            exchange_rate = 1.00  # Default to 1.00 if currencies are the same

            if active_currency.code != payment_currency:
                exchange_rate = active_currency.exchange_rate_to_usd
                payment_amount = payment_amount / exchange_rate

            # Process payment via Stripe
            try:
                PaymentService.initiate_payment(order, payment_amount, payment_currency)
            except Exception as e:
                return render(request, 'pos/orders/checkout.html', {
                    'order': order,
                    'modal_message': f'Erreur lors du traitement du paiement: {str(e)}',
                    'currency': active_currency,
                    'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
                })

            received_amount = payment_amount
            change = Decimal('0.00')

        # Create the Bill record
        bill = Bill.objects.create(
            order=order,
            bill_id=f'{order.id}-{timezone.now().strftime("%Y%m%d%H%M%S")}',
            payment_method=payment_method,
            payment_amount=payment_amount,
            received_amount=received_amount,
            change_amount=change
        )

        # Finalize the order
        order.user = request.user
        order.payment_method = payment_method
        order.status = 'completed'
        order.save()

        # Update user profile and handle notifications
        self.update_user_profile_and_notifications(order, request.user)

        return render(request, 'pos/orders/checkout_complete.html', {
            'order': order,
            'bill': bill,
            'received_amount': received_amount,
            'change': change,
            'currency': active_currency,
            'stripe_publishable_key': settings.STRIPE_PUBLISHABLE_KEY
        })

    def update_user_profile_and_notifications(self, order, user):
        """Update user profile's daily balance and create notifications."""
        today = timezone.now().date()
        user_profile = user.profile

        # Reset the daily balance if needed
        if user_profile.last_balance_reset != today:
            user_profile.daily_balance = Decimal('0.00')
            user_profile.last_balance_reset = today
        user_profile.daily_balance += order.total_amount_with_tax
        user_profile.save()

        # Notify the user
        Notification.objects.create(
            user=user,
            message=f'Solde du jour mis à jour: {user_profile.daily_balance:.2f} {order.items.first().product_batch.product.currency.symbol}',
            notification_type='balance_update'
        )

        # Handle stock alerts
        stock_alert_roles = ['General_Manager', 'Manager', 'Stock_Controller', 'Supervisor']
        if user_profile.roles.filter(name__in=stock_alert_roles).exists():
            for item in order.items.all():
                if item.product_batch.should_send_alert():
                    Notification.objects.create(
                        user=user,
                        message=self.generate_stock_alert_message(item.product_batch),
                        notification_type='stock_alert'
                    )

    def generate_stock_alert_message(self, product_batch):
        """Generate a stock alert message based on stock levels."""
        if product_batch.stock <= product_batch.product.minimum_stock_level:
            return f"Alerte de stock faible pour {product_batch.product.name} (Seulement {product_batch.stock} restants !)"
        elif product_batch.stock <= product_batch.product.low_stock_level:
            return f"Le stock est faible pour {product_batch.product.name} ({product_batch.stock} restants !)"
        return ""

{% load multiply %}
{% load static %}
<!DOCTYPE html>
<html lang="fr">
<head>
    <title>Checkout</title>

    <!-- Stylesheets -->
    <link rel="stylesheet" href="{% static 'css/bootstrap4.min.css' %}">
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'css/font-awesome.min2.css' %}">
    <link rel="stylesheet" href="{% static 'css/all.min.css' %}">
    <!-- Include Select2 CSS -->
    <link href="{% static 'css/select2.min.css' %}" rel="stylesheet" />

    <!-- jQuery -->
    <script src="{% static 'js/jquery-3.2.1.min.js' %}"></script>

    <!-- Custom Styles -->
    <style>
        body {
            display: flex;
            height: 100vh;
            margin: 0;
            font-family: Arial, sans-serif;
            background-color: #f8f9fa;
        }

        /* Sidebar styling */
        .sidebar {
            width: 200px; /* Reduced from 250px */
            background-color: #2A3F54;  /* Dark Slate */
            padding-top: 20px;
            position: fixed;
            height: 100%;
            transition: width 0.3s ease;
        }


        .sidebar.collapsed {
            width: 70px;
        }

        .sidebar .nav-link {
            color: white;
            margin: 10px;
            white-space: nowrap;
            overflow: hidden;
            transition: all 0.3s ease;
        }

        .sidebar.collapsed .nav-link {
            text-align: center;
            padding: 10px 0;
        }

        .sidebar.collapsed .nav-link span {
            display: none;
        }

        .sidebar .nav-link:hover {
            background-color: #34495e;
            border-radius: 4px;
        }

        .sidebar .nav-link i {
            margin-right: 10px;
        }

        .sidebar.collapsed .nav-link i {
            margin-right: 0;
        }

        /* Top navbar styling */
        .top-navbar {
            background-color: #3C8DBC;  /* Light blue */
            color: white;
            width: calc(100% - 200px); /* Adjusted for the new sidebar width */
            margin-left: 200px; /* Adjusted for the new sidebar width */
            position: fixed;
            top: 0;
            z-index: 1030;
            transition: margin-left 0.3s ease, width 0.3s ease;
        }

        /* Content area styling */
        .content {
            margin-left: 200px; /* Adjusted for the new sidebar width */
            margin-top: 10px;  /* Adjust for navbar height */
            padding: 100px;
            width: calc(100% - 200px); /* Adjusted for the new sidebar width */
            transition: margin-left 0.3s ease, width 0.3s ease;
        }

        .collapsed + .top-navbar {
            margin-left: 70px; /* Maintains behavior for collapsed sidebar */
            width: calc(100% - 70px);
        }

        .collapsed ~ .content {
            margin-left: 70px; /* Maintains behavior for collapsed sidebar */
            width: calc(100% - 70px);
        }

        .toggle-icon {
            cursor: pointer;
            font-size: 1.5rem;
        }

        /* Table styling */
        .table th, .table td {
            vertical-align: middle;
        }

        .form-control {
            margin-bottom: 15px;
        }

        /* Button styling */
        button {
            margin-top: 10px;
        }
    </style>
</head>
<body>
    
    <!-- Content Section -->
    <div class="content">
        <div class="row">
            <div class="col-md-8">
                <label align="center">Commande N° {{ order.id }}</label>
                <div class="table-responsive">
                    <table class="table table-striped">
                        <thead>
                            <tr>
                                <th>Produit</th>
                                <th>Quantité</th>
                                <th>Prix unitaire</th>
                                <th>Total</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for item in order.items.all %}
                            <tr>
                                <td>{{ item.product_batch.product.name }}</td>
                                <td>{{ item.quantity }}</td>
                                <td>
                                    {% if item.product_batch.discounted_price %}
                                        {{ item.product_batch.discounted_price }} {{ currency.symbol }}
                                    {% else %}
                                        {{ item.product_batch.price }} {{ currency.symbol }}
                                    {% endif %}
                                </td>
                                <td>
                                    {% if item.product_batch.discounted_price %}
                                        {{ item.quantity|multiply:item.product_batch.discounted_price|floatformat:2 }} {{ currency.symbol }}
                                    {% else %}
                                        {{ item.quantity|multiply:item.product_batch.price|floatformat:2 }} {{ currency.symbol }}
                                    {% endif %}
                                </td>
                            </tr>
                            {% endfor %}
                        </tbody>
                        <tfoot>
                            <tr>
                                <td colspan="3" class="text-right"><strong>Total à payer:</strong></td>
                                <td><strong>{{ order.total_amount_with_tax|floatformat:2 }} {{ currency.symbol }}</strong></td>
                            </tr>
                        </tfoot>
                    </table>
                </div>
            </div>

            <!-- Payment Section -->
            <div class="col-md-4">
                <form id="checkout-form" method="post">
                    {% csrf_token %}
                    <!-- Mode de Paiement -->
                    <div class="form-group">
                        <label for="payment_method">Mode de Paiement</label>
                        <select class="form-control" id="payment_method" name="payment_method" required>
                            <option value="cash" selected>Cash</option>
                            <option value="credit_card">Credit Card</option>
                            <option value="debit_card">Debit Card</option>
                            <option value="holo">Holo</option>
                            <option value="huri_money">Huri Money</option>
                        </select>
                    </div>

                    <!-- Discount Type -->
                    <div class="form-group">
                        <label for="discount_type">Type de réduction</label>
                        <select class="form-control" id="discount_type" name="discount_type">
                            <option value="">Aucune</option>
                            <option value="rabais">Rabais</option>
                            <option value="remise">Remise</option>
                            <option value="ristourne">Ristourne</option>
                        </select>
                    </div>

                    <!-- Discount Amount -->
                    <div class="form-group">
                        <label for="discount_amount">Montant de la réduction</label>
                        <input type="number" class="form-control" id="discount_amount" name="discount_amount" min="0" step="0.01" value="0.00">
                    </div>

                    <!-- Montant reçu (for cash payment) -->
                    <div class="form-group" id="cash-payment">
                        <label for="received_amount">Montant reçu</label>
                        <input type="number" class="form-control" id="received_amount" name="received_amount" min="0" step="0.01">
                        <small id="change" class="form-text text-muted"></small>
                    </div>

                    <!-- Payment card fields for Stripe -->
                    <div id="card-element" class="form-group" style="display:none;">
                        <!-- A Stripe Element will be inserted here. -->
                    </div>
                    <div id="card-errors" role="alert" class="form-text text-danger"></div>
                    <button type="submit" class="btn btn-success btn-block">Confirmer la commande</button>
                </form>
            </div>
        </div>
    </div>

    <!-- Stripe Integration & Checkout Form Handling -->
    <script src="https://js.stripe.com/v3/"></script>
    <script>
        $(document).ready(function () {
            console.log("Initializing Stripe...");

            try {
                // Initialize Stripe
                var stripe = Stripe("{{ stripe_publishable_key }}");
                var elements = stripe.elements();

                // Create a card element
                var card = elements.create('card', {
                    style: {
                        base: {
                            fontSize: '16px',
                            color: '#32325d',
                            '::placeholder': { color: '#aab7c4' }
                        },
                        invalid: {
                            color: '#fa755a',
                            iconColor: '#fa755a'
                        }
                    }
                });

                // Mount the card element
                card.mount('#card-element');

                // Function to toggle payment fields
                function togglePaymentFields() {
                    var paymentMethod = $('#payment_method').val();
                    console.log("Selected payment method:", paymentMethod);

                    if (paymentMethod === 'cash') {
                        $('#cash-payment').show();
                        $('#card-element').hide();
                        card.unmount(); // Ensure card fields are unmounted
                        $('#received_amount').val('');
                        $('#change').text('');
                    } else if (paymentMethod === 'credit_card' || paymentMethod === 'debit_card') {
                        $('#cash-payment').hide();
                        $('#card-element').show();
                        card.mount('#card-element'); // Remount card fields
                    } else {
                        $('#cash-payment').hide();
                        $('#card-element').hide();
                        card.unmount();
                    }
                }

                // Initialize the field toggle
                togglePaymentFields();

                // Trigger toggle on payment method change
                $('#payment_method').change(function () {
                    togglePaymentFields();
                });

                // Update change amount dynamically
                $('#received_amount').on('input', function () {
                    var received = parseFloat($(this).val());
                    var total = parseFloat("{{ order.total_amount_with_tax }}");

                    if (!isNaN(received) && received >= total) {
                        var change = received - total;
                        $('#change').text('Montant à retourner: ' + change.toFixed(2) + ' {{ currency.symbol }}');
                    } else {
                        $('#change').text('');
                    }
                });

                // Handle form submission
                $('#checkout-form').submit(function (e) {
                    var paymentMethod = $('#payment_method').val();

                    if (paymentMethod === 'cash') {
                        var received = parseFloat($('#received_amount').val());
                        var total = parseFloat("{{ order.total_amount_with_tax }}");
                        var discountAmount = parseFloat($('#discount_amount').val()) || 0;

                        total -= discountAmount;

                        if (isNaN(received) || received < total) {
                            alert('Le montant reçu est insuffisant.');
                            e.preventDefault();
                        }
                    } else if (paymentMethod === 'credit_card' || paymentMethod === 'debit_card') {
                        e.preventDefault();

                        stripe.createPaymentMethod({
                            type: 'card',
                            card: card
                        }).then(function (result) {
                            if (result.error) {
                                console.error("Error creating payment method:", result.error.message);
                                $('#card-errors').text(result.error.message);
                            } else {
                                $.post("{% url 'posApp:create_stripe_payment_intent' order.id %}", {
                                    'csrfmiddlewaretoken': '{{ csrf_token }}',
                                    'discount_type': $('#discount_type').val(),
                                    'discount_amount': $('#discount_amount').val()
                                }).done(function (data) {
                                    stripe.confirmCardPayment(data.client_secret, {
                                        payment_method: result.paymentMethod.id
                                    }).then(function (result) {
                                        if (result.error) {
                                            console.error("Error confirming payment:", result.error.message);
                                            $('#card-errors').text(result.error.message);
                                        } else if (result.paymentIntent.status === 'succeeded') {
                                            $('#checkout-form').off('submit').submit();
                                        }
                                    });
                                });
                            }
                        });
                    }
                });

            } catch (err) {
                console.error("Error initializing Stripe or setting up payment fields:", err);
                alert("An error occurred while setting up the payment system. Check the console for details.");
            }
        });
    </script>




    <!-- Sidebar Collapse/Expand -->
    <script>
        document.getElementById('fusionPro').addEventListener('click', function() {
            var sidebar = document.getElementById('sidebar');
            var icon = document.getElementById('toggle-icon');

            sidebar.classList.toggle('collapsed');
            
            if (sidebar.classList.contains('collapsed')) {
                icon.classList.remove('fa-bars');
                icon.classList.add('fa-chevron-right');
            } else {
                icon.classList.remove('fa-chevron-right');
                icon.classList.add('fa-bars');
            }
        });
    </script>

    <!-- Bootstrap and other scripts -->
    <script src="{% static 'js/popper.min.js' %}"></script>
    <script src="{% static 'js/bootstrap5.bundle.min.js' %}"></script>
    <script src="{% static 'js/all.min.js' %}"></script>

    <!-- Include Select2 JavaScript -->
    <script src="{% static 'js/select2.min.js' %}"></script>

</body>
</html>

Can someone tell me what I’ve to do or what I have to change in order to make this code (.py and thml) working in Ubuntu?

React Error: Element type is invalid when rendering a list of results from API

I’m trying to fetch city data using the OpenCage API and display the results in a list using React and Chakra UI. However, I’m getting the following error: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. I use page routing. This is my code:

import NextLink from "next/link";
import { useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");
  const [results, setResults] = useState([]);

  const handleSearch = async () => {
    if (!searchTerm.trim()) return;

    const response = await fetch(
      `https://api.opencagedata.com/geocode/v1/json?q=${searchTerm}&key=YOUR_API_KEY`
    );
    const data = await response.json();

    const cityResults = data.results.map((result) => ({
      id: `${result.geometry.lat},${result.geometry.lng}`,
      name: result.formatted,
      lat: result.geometry.lat,
      lng: result.geometry.lng,
    }));

    setResults(cityResults);
  };

  return (
    <Box>
      <Text>Search for a city</Text>
      <Input value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} />
      <Button onClick={handleSearch}>Search</Button>
      <List>
        {results.map((city) => (
          <ListItem key={city.id}>
            <NextLink href={`/city/${city.id}`} passHref>
              <Link>{city.name}</Link>
            </NextLink>
          </ListItem>
        ))}
      </List>
    </Box>
  );
}

When I attempt to render the results, I get the error Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
I’ve tried using forEach() instead of map(), checked if I’m importing the components correctly, and ensured that the data returned from the API is in the expected format, but the issue persists.
I’ve checked the imports of NextLink, List, and ListItem.
Is working fine showing only one result with the following code:


  const [searchTerm, setSearchTerm] = useState("");
  const [result, setResult] = useState(null); 

 .....

      const firstCity = data.results[0]; // Take only the first result
      const city = {
        id: `${firstCity.geometry.lat},${firstCity.geometry.lng}`,
        name: firstCity.formatted,
        lat: firstCity.geometry.lat,
        lng: firstCity.geometry.lng,
      };

      setResult(city);
      console.log("Result:", city);
    } catch (error) {
      console.error("Error fetching data:", error);
      alert("Something went wrong. Please try again.");
    }
  };

  return (
    <>
     ....
        
          <Box mt={8} px={4}>
        {result ? (
          <Box>
            <Text fontSize="lg">
              <NextLink href={`/city/${result.id}`} passHref>
                <Link color="teal.500">
                  {result.name} (Lat: {result.lat}, Lng: {result.lng})
                </Link>
              </NextLink>
            </Text>
          </Box>
        ) : (
          <Text>No results found</Text>
        )}
      </Box>
    </>
  );
}

Any help is greatly appreciated!

How can I play video with H264 – MPEG-4 AVC (part 10) (h264) codec using tag

I am writing angular app to stream videos returned from backend. These videos are live streams that I tested that work using VLC Media Player > Open Network Stream without any issues.

Codec returned looks like this:

enter image description here

I am using video html element where I set the src of source to returned link from the backend:

<video #videoPlayer id="video" preload="auto" muted>
 <source #videoSrc type="video/mp4">
 Your browser does not support the video tag.
</video>

Can I play videos with codec like this on web browsers?

Event.preventDefault is not working in JS for form submission

// js

document.addEventListener("DOMContentLoaded", function () {
        const individualOrderForm = document.getElementById('individual-order-form');

        async function sendAjax(form) {
            try {
                const response = await fetch(form.action, {
                    method: 'POST',
                    body: new FormData(form)
                });

                const data = await response.json();

                if (data.status === "success") {
                    showToast(data.detail, "success");
                    disableForm(form);
                } else {
                    let errors = JSON.parse(data.errors);
                    let errorsText = Object.entries(errors)
                        .map(([field, errors]) => {
                            return errors.map(error => `${error.message}`).join('n');
                        })
                        .join('n');

                    showToast(`${data.detail}n${errorsText}`, "danger");
                }
            } catch (error) {
                console.log(error);
                showToast(gettext("Произошла ошибка. Повторите попытку позже."), "danger");
            }
        }

        individualOrderForm.addEventListener(
            'submit',
            function (e) {
                e.preventDefault();
                sendAjax(individualOrderForm);
            },
            {passive: false}
        );
    }
);
<form id="individual-order-form"
      action="{% url 'mainpage:individual-order-negotiate' %}"
      method="POST"
      class="d-flex w-100 flex-column justify-content-start align-items-start text-start card-body">
  <fieldset class="w-100">
    <legend class="text-center">
      <h2 class="fs-4 fw-normal" id="contact-us">
        {% translate 'Свяжитесь с нами' %}
      </h2>
    </legend>
    <div class="form-text">{% translate 'Заполните форму, чтобы заказать букет из индивидуального состава.' %}</div>
    {% csrf_token %}
    <div class="mb-3 w-100">
      <label for="customerNameInput" class="form-label">{% translate 'Имя' %}</label>
      <input class="form-control text-start" id="customerNameInput" aria-describedby="nameHelp" name="first_name"
        required>
    </div>
    <div class="mb-3">
      <label for="contact-method-input" class="form-label">
        {% translate 'Тел. номер в любой соц. сети или ссылка профиля' %}
      </label>
      <div class="d-flex">
        {{ individual_order_form.contact_method }}
      </div>
    </div>
    <div class="mb-3 form-check">
      <input type="checkbox" class="form-check-input checkbox-dark" id="recallCheckbox" name="recall_me">
      <label class="form-check-label" for="recallCheckbox">
        <small>
          {% translate 'Разрешаю мне перезвонить' %}
        </small>
      </label>
    </div>
    <button class="btn btn-dark-green">{% translate 'Связаться' %}</button>
  </fieldset>
</form>

Unfortunately, on iOS (at least on iOS), the following code does not work as expected:

individualOrderForm.addEventListener(
    'submit',
    function (e) {
        e.preventDefault();
        sendAjax(individualOrderForm);
    },
    { passive: false }
);

When submitting the form via a POST request, the page is redirected to the URL where the POST request is sent, and I see the returned JSON object displayed on a black screen.

However, this works perfectly on both PC and Android devices.

Regrettably, I am unable to resolve this issue.

I came across this discussion, which seemed like a logical solution, but unfortunately, it did not resolve the problem:

GitHub Discussion: React Issue #13369.

I have already tried clearing the cache on both the client and server sides, running manage.py collectstatic, and restarting the server, but the issue persists.

Any assistance or guidance would be greatly appreciated.

Use Dexie to export certain data from a table in a database

I am using Quasar and JavaScript with a Dexie Database. I’m trying to export only certain items from the database.

My application has events that contain trials. I have an event table and a trial table. (also more tables, but for now this will be enough) The database is getting pretty large with all the events, so I want to be able to export the events with the related trial information from the trial table so they can be stored. Then eventually delete those events and trials.

I’m using the following:

import "dexie-export-import"
import { exportDB } from "dexie-export-import"
import download from 'downloadjs'

I have a select field which allows the user select which event to export. Then I run it through the exportDB and download the file. This works fine:

const getStuffToExport = await exportDB(pawTapDB, {
   prettyJson: true 
   filter: (table, value, key) => table === "trialTable", 
})

download(getStuffToExport, "PawTapBackupFile.json", "application/json")

This gets the entire table. But I only want data that contains the event from the selection. This is a snippet from the JSON file that is being downloaded/exported:

{
      "tableName": "trialTable",
      "inbound": true,
      "rows": [
        {
          "fk_event": 1,
          "trialNum": 1,
          "trialDate": "2022-06-04",
          "trialEventNumber": "2022745113",
          "buried": {
            "buriedNoviceOffered": true,
            "buriedNoviceJudge": 3,
.....

What I need to do is filter it further so that I get only the table entries that have the fk_event that I am looking for. So for example I only want the table rows where the fk_event == 1.

Is this possible?

In the filter function in Dexie it has three values: table, value, key. I’m not actually sure what the value and the key is. I can’t find an example of those anywhere. The table is, obviously, the table name. Can I use value or key to further reduce my selection?
Thanks

How to style the Prime-React’s component “FloatLabel”?

In the LoginPage of my website, the input fields use the FloatLabel component:
initial state image.

When the label floats on top, it blends with the background:
final state image.

I’m trying to change it’s color only when it floats up.
Is there any way to do it?

I’m using the latest version of React and Prime React; here’s where I use the component:

<FloatLabel>
    <InputText
         id="username"
         type="text"
         value={username}
         onChange={(e) => setUsername(e.target.value)}
     />
     <label htmlFor="username">Username</label>
</FloatLabel>

I tried adding these properties in the css file:

.custom-float-label .p-float-label label {
  transition: color 0.3s;
}

.custom-float-label .p-float-label label.p-float-label-active {
  color: black;
}

but nothing happens

How to stop triggering the event listener callback function on the button click?

I have feature where as I scroll I automatically select the card that is in view port, also I have another feature where there are 2 buttons “Prev” and “Next” and when i click it will go to the next or prev card and bring that into the view port. But when i click my event listener callback is also getting triggered, I want to trigger my event listener only when I scroll, not when I click on “Prev” and “Next”
Below is my code where I have the Scroll event listener and the OnClick for Prev and Next.
I tried Using both ref and state to see the updated value inside handleScroll but first time I am getting the correct value and again for some reason it was getting triggered 2nd time again with false for `isButtonScrolling.current`, I suspect it was after due to scrollintoView that happened inside the store. I event tried to do event.stopPropagation() but that did not work as well.

import { Grid, LinearProgress, Typography } from '@mui/material';
import { makeStyles } from '@mui/styles';
import { useAppDispatch, useAppSelector } from '@store/StoreTypedHooks';
import PreviousButton from './PreviousButton';
import NextButton from './NextButton';
import useDeviceType from '@hooks/useDeviceType';
import { answeredQuestionCount, expandCollapse, totalQuestionCount } from '@store/respondStore/RespondStoreSelectors';
import { useEffect, useRef, useState } from 'react';
import { updateCurrentQuestionOnScroll, updatePreviousNextQuest } from '@store/respondStore/RespondStoreThunks';
import QuestionScrollObserever from './QuestionScrollObserver';
import { debounce } from '@utils/GeneralUtils';

export default function RespondPageHeader() {
  const classes = RespondPageStyles();
  const dispatch = useAppDispatch();
  const totalCount = useAppSelector(totalCardCount);
  const totalComputedCount = useAppSelector(computedCount);
  const expandCollapseOption = useAppSelector(expandCollapse);
  const progressValue = (totalComputedCount / totalCount) * 100;
  const { isMobileTab, isMobile } = useDeviceType();

  const isButtonScrolling = useRef(false);

  const isElementInViewport = (element: HTMLElement, containerRect: any) => {
    const rect = element.getBoundingClientRect();
    return (
      rect.left >= 0 &&
      rect.bottom <= containerRect.bottom &&
      rect.right <= containerRect.right
    );
  };

  const isContainerScrolledToEnd = (container: HTMLElement) => {
    return container.scrollHeight - container.scrollTop === container.clientHeight;
  };

  const getTopCardId = (scrollLock: boolean) => {
    if (scrollLock || expandCollapseOption !== 'EXPAND') {
      console.log('Skipping scroll processing - Button scroll active:', isButtonScrolling.current);
      return;
    }

    const container = document.getElementById('question_scroll_observer');
    if (!container) return;

    const cards = container.getElementsByClassName('card');
    const containerRect = container.getBoundingClientRect();

    let maxVisibility = 0;
    let selectedCardId = null;

    for (let card of cards) {
      const questionElement = card.querySelector('.question');

      if (!questionElement || !isElementInViewport(questionElement, containerRect)) {
        continue;
      }

      const cardRect = card.getBoundingClientRect();
      const cardVisibleHeight = Math.min(cardRect.bottom, containerRect.bottom) - Math.max(cardRect.top, containerRect.top);
      const visiblePercentage = cardVisibleHeight / cardRect.height;

      if (visiblePercentage > maxVisibility) {
        maxVisibility = visiblePercentage;
        selectedCardId = card.id.replace('question_card_', '');
      }
    }

    if (isContainerScrolledToEnd(container)) {
      const lastCard = cards[cards.length - 1];
      if (lastCard) {
        selectedCardId = lastCard.id.replace('question_card_', '');
      }
    }

    if (selectedCardId) {
      dispatch(updateCurrentQuestionOnScroll({ questionId: selectedCardId }));
    }
  };

  const handleScroll = () => {
    console.log('Scroll event fired - Button scroll active:', isButtonScrolling.current);
    if (!isButtonScrolling.current) {
      getTopCardId(isButtonScrolling.current);
    }
  };

  const goToPreviousNextSection = (type: string) => {

    isButtonScrolling.current = true;

    // Dispatch navigation action where I scroll to the card either next card or prev card based on the type I am getting in parameters and to scroll to the card I use scrollIntoView for that particular card id
    dispatch(updatePreviousNextQuest({ changeQuestion: type }));

    // Set timeout to reset ref
    const scrollTimeout = setTimeout(() => {
      isButtonScrolling.current = false;
      clearTimeout(scrollTimeout)
    }, 1000);
  };

  // Set up scroll event listener
  useEffect(() => {
    const container = document.getElementById('question_scroll_observer');

    if (container) {
      container.addEventListener('scroll', handleScroll);

      return () => {
        container.removeEventListener('scroll', handleScroll);
      };
    }
  }, []);

  return (
    <Grid className={`panel-color h-52 flex`}>
      <div className={`p-24 pl-10p pr-12p flex layout-row w-full items-center ${isMobileTab && 'justify-between'}`}>
        {isMobileTab && (
          <Grid className='pr-8p'>
            <PreviousButton onChange={() => goToPreviousNextSection("PREVIOUS")} />
          </Grid>
        )}
        <Grid className='pr-8p'>
          <Typography className='radiant-green-text text-base'>
            {`${totalCount - answeredCount} questions left`}
          </Typography>
        </Grid>
        {!isMobile && (
          <Grid className='layout-flex'>
            <LinearProgress
              value={progressValue}
              variant='determinate'
              className={classes.progressBarStyle}
            />
          </Grid>
        )}
        <Grid className='flex justify-between'>
          {!isMobileTab && (
            <PreviousButton onChange={() => goToPreviousNextSection("PREVIOUS")} />
          )}
          <NextButton onChange={() => goToPreviousNextSection("NEXT")} />
        </Grid>
      </div>
    </Grid>
  );
}

What is the difference between let, var, and const in JavaScript? [duplicate]

I understand the basics of let, var, and const in JavaScript, but I’m curious about the more advanced nuances and edge cases. Here’s what I’m exploring deeper into some advanced aspects:

Scope: How do block-scoping (let and const) and function-scoping (var) behave in nested contexts or closures?
Hoisting: Why do let and const remain in the temporal dead zone, and how can this lead to runtime errors?
Re-declaration: How do let and const restrictions on re-declaration impact variable shadowing?
Mutation: How do you enforce immutability for objects or arrays declared with const?
Best Practices: Are there cases where using var is still appropriate in modern JavaScript?

Angular 17 & @angular/[email protected] // MapClick directive not firing in map-marker

First of all i’m new to google map, it’s my first time using it, i try to get the marker’s on the map when i trigger a click on it, my goal for my app’s is to get one mark done by the client, then i give it back to his artisan to redraw the marker, then try to polygone the way back from the poisition A to B by the artisan.

First try to get the marker failed, i’m stucked here, my wish is to get the marker done, that’s will be great.

I’m having an issue with an event firing as explained in the title, map-marker is somehow not giving any response eventDOM.
here is my component.ts and html.

<google-map
  [height]="height"
  [width]="width"
  [zoom]="mapOptions.zoom!"
  [options]="mapOptions"
  [center]="mapOptions.center!"
  (mapInitialized)="handleMapInitialized($event)">

  <map-marker
    (mapClick)="openMapInfo(marker.getTitle()!, mapMarker)"
    #mapMarker="mapMarker"
    *ngFor="let marker of markers"
    [position]="marker.getPosition()!"
    [title]="marker.getTitle()!"
    />
  
  <map-info-window>{{ infoContent }}</map-info-window>

  <map-polyline [options]="polylineOptions" ></map-polyline>
</google-map>

import { Component, Input, ViewChild, type OnInit } from '@angular/core';
import { GoogleMap, MapInfoWindow, MapMarker } from '@angular/google-maps';

@Component({
  selector: 'app-api-gm',
  templateUrl: './API-GM.component.html',
  styleUrl: './API-GM.component.css',
})
export class APIGMComponent implements OnInit {
  @ViewChild(MapInfoWindow, { static: false }) infoWindow?: MapInfoWindow;

  @Input() locationFrom?: any;
  @Input() locationTo?: any;

  height: string = '600px';
  width: string = '1200px';
  mapOptions: google.maps.MapOptions = {
    center: {
      lat: 0,
      lng: 0
    },
    mapId: '9af0088ade5e5e42',
    scrollwheel: true,
    disableDoubleClickZoom: false,
    //mapTypeId: 'roadmap',
    zoom: 15,
    maxZoom: 25,
    minZoom: 1,

  };

  markers: Set<google.maps.Marker> = new Set();

  infoContent: string = '';

  polylineOptions: google.maps.PolylineOptions = {
    path: [],
    strokeColor: '#F78F08',
    strokeOpacity: 1.0,
    strokeWeight: 5,
    draggable: false
  }

  ngOnInit(): void {
    this.getCurrentPosition();
  }
  handleMapInitialized(map: google.maps.Map) {}
  getCurrentPosition(): void {
    navigator.geolocation.getCurrentPosition((position) => {
      this.mapOptions.center = {
        lat: position?.coords.latitude ?? 46.788,
        lng: position?.coords.longitude ?? -71.3893,
      }
    });
  }

  ngOnChanges(): void {
    if (this.locationFrom) {
      this.addMarker(this.locationFrom);
    }

    if (this.locationTo) {
      this.addMarker(this.locationTo);
    }

    if (this.hasLocation) {
      this.addPolyline();
    }
  }

  get hasLocation(): boolean {
    return !!this.locationFrom && !!this.locationTo;
  }

  loadMarker(location?: any): google.maps.Marker {
    return new google.maps.Marker({
      position: {
        lat: location?.latitude ?? 0,
        lng: location?.longitude ?? 0
      },
      title: location?.name ?? '',
      animation: google.maps.Animation.DROP,
      draggable: true,
    });
  }

  addMarker(location: any): void {
    const marker = this.loadMarker(location);
    this.markers.add(marker);
    this.moveMapView();
  }

  moveMap(event: any): void {
    if (event.latLng != null) {
      this.mapOptions.center = (event.latLng.toJSON());
    }
    //let loc = {lat : this.MapMarker.getPosition()?.lat, lng : this.MapMarker.getPosition()?.lng };
    //console.log(loc);
    //this.addMarker()
  }

  moveMapView(): void {
    this.mapOptions.center = {
      lat: this.locationFrom?.latitude ?? 0,
      lng: this.locationFrom?.longitude ?? 0
    }
  }

  openMapInfo(content: string, marker: MapMarker): void {
    const myLatLng = { lat: marker.getPosition()!.lat(), lng: marker.getPosition()!.lng() };
    console.log(myLatLng);
    this.infoContent = content;
    this.infoWindow?.open(marker);
    let marker0 = new google.maps.Marker ({
      position: myLatLng,
    });
    this.markers.add(marker0);

  }
  addmarker(mylatlng: any): void {   
    let marker0 = new google.maps.Marker ({
      position: mylatlng,
    });
    this.markers.add(marker0);

  }

  addPolyline(): void {
    const markers = Array.from(this.markers).slice(-2);
    const path: google.maps.LatLng[] = [];
    markers.forEach((marker, index) => {
      path.push(new google.maps.LatLng(marker.getPosition()!));
    });
    this.polylineOptions = { ...this.polylineOptions, path };
    this.markers = new Set(markers);
  }
}

i’ve try’d some tricks : put the mapClick outside the for loop and inside, different events drags/drops/dblclick etc.

I’v kept trying to call the MapMarker by a viewchild to get the positions params and got to another call outside to put the marker on the map, i didn’t succes.

Create a Stream using MP3s

I have some code that generates a script using the OpenAI API and then converts the script to an MP3 using a text to audio API. My code runs every five minutes and ensures there is never ending queue of MP3 files.

I then have an HTML/JavaScript player that plays the next MP3 in the queue and then deletes it.

However, I want this to run like a live stream. How do I convert the queue of MP3s to an audio stream. This way if multiple people are listen, they are hearing the exact same thing at the same time.

My Iframe Won’t Load Correctly, And Is Not The Right Size

I am trying to make the icons work so that when I click on them, they open an iframe that contains the page that I want to go to so that the actual URL never changes, but the user can still access the subpages of the website. I set the “onclick=beep()” to the page I wanted it to appear as, but I instead just sends me to the website’s main page. I will include screenshots to show what I mean. The iframe also only takes up the very top of the page, instead of taking up the whole page.

Website Before
Website before clicking the icon

Website After
Website after clicking the icon

What did I do wrong?

function beep(x) {
    var iframe = document.createElement("iframe")
    var html = "<body>Foo</body>"
    document.getElementById('all').hidden = true
    iframe.src = x + encodeURI(html)
    document.body.appendChild(iframe)
  }  
body {
    background: radial-gradient(circle at bottom, #4D511F 0, #03260c 100%);}

h1{
    margin:auto;
    text-align: center;
    font-weight: 400;
    font-style: normal;
    font-size: 5vw;
    color: #D0BF94;
}

.grid {
    display: grid;
    grid-template-columns: auto auto auto auto;
    margin-top: 5%;
    margin-left: 5%;
    max-width: 100% !important;
    column-gap: 5vw;
    row-gap: 5vw;
    margin-right: 5%;
}

.game {
    width:10%;
    height:10%;
}

img {
    width:17vw;
}

iframe {
    width: 100%;
    height: 100%;
    border: none;
}
<div id="all">
      <h1>Website</h1>
      
      <div class="grid">
        <div class="game"><img src="images/goedash.png" alt="Geometry Dash" onclick="beep('example.github.io/pages/geodash/index.html')"></div>
        <div class="game"><a href=""><img src="" alt=""></a></div>
        <div class="game"><a href=""><img src="" alt=""></a></div>
      </div>

Can we conditionally manage the dynamic config value in the app router page (next.js 14)?

I was trying to add this on a page:

export const dynamic = process.env.NEXT_PUBLIC_PLATFORM === "mobileApplication" ? "force-static" : "auto";

But I came across this warning and red underline:

TS71003: “process. env. NEXT_PUBLIC_PLATFORM === “mobileApplication” ?
“force-static” : “auto”” is not a valid value for the “dynamic”
option. The configuration must be statically analyzable.

But it seems that this condition will work, but I don’t know what this error is talking about

SvelteKit – Redirect after Form Submit

I have a problem with redirecting after submitting form in SvelteKit.

I have some routes that needs authentication, before rendering it I’m checking if user is authenticated.

routes
│       ├── +page.svelte
│       ├── login
│       │   ├── +page.server.ts
│       │   └── +page.svelte
│       └── movies
│           ├── +page.server.ts
│           ├── +page.svelte
│           └── [id]
│               ├── +page.server.ts
│               ├── +page.svelte
│               └── +page.ts

For example, when user vistits /movies route, in my +page.server.ts I’m checking if user is authenticated, by lookup in cookies. If cookies haven’t auth_token I’m redirecting him to /login route with some info about desired redirecting route after succesful login.

So in that scenario, user will be redirected to /login?redirectTo=%2Fmovies

For that part, everything works great.

The idea is that, if he authenticate it should redirect him again to /movies route.

I wrote some logic in routes/login/+page.server.ts to gather value of redirectTo query param but after submitting form I can’t see it.

/routes/login/+page.server.ts

import { redirect } from '@sveltejs/kit';

    export const actions = {
        login: async ({request, cookies, url}) => {
            
            console.log("url", url)
            console.log('request', request)
            const formData = await request.formData();
            const data = { email: formData.get('email'), password: formData.get('password')}

            

                const response = await fetch("http://localhost:4000/v1/tokens/authentication", {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(data),
                    credentials: 'include'
                })

                if (!response.ok) {
                    return {success: false};
                }
                
                const cookie = response.headers.get('set-cookie');
                if (cookie !== null) {
                const parts = cookie.split(';');
                const token = parts[0].split('=')[1];
                const expires = parts.find(p => p.trim().startsWith('Expires'))?.split('=')[1];

                cookies.set('auth_token', token, {
                    path: '/',
                    httpOnly: true,
                    sameSite: 'lax',
                    expires: expires ? new Date(expires) : undefined
                });

            
                console.log(url.searchParams)

                
                const redirectTo = url.searchParams.get('redirectTo') || '/'
                console.log("redirectTo", redirectTo)
                redirect(303, redirectTo);

                return {
                    
                    success: true,
                }
                
            
            } return {
                success: false,
            }
            
                
            
        }
}

/routes/login/+page.svelte

<script lang="ts">
  import { enhance } from "$app/forms";
</script>

<h1>Login</h1>
<form method="POST" action="?/login" use:enhance>
  <label
    >Email
    <input name="email" type="email" required />
  </label>
  <label
    >password
    <input name="password" type="password" required />
  </label>
  <button>Log in</button>
</form>

The output of console.log("url", url) is missing that URL with redirectTo value.

url URL {
  href: 'http://localhost:5173/login?/login',
  origin: 'http://localhost:5173',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'localhost:5173',
  hostname: 'localhost',
  port: '5173',
  pathname: '/login',
  search: '?/login',
  searchParams: URLSearchParams { '/login' => '' },
  hash: ''
}

What Am I doing wrong? I followed logic from docs.

Prevent full page load when clicking the forward button with popstate event

I’m creating a SPA that has multiple pages that have some hierarchy. The user can click on any item in a list to see details (going forward) and on the details page can click a “back” button on the page to return to the list view.

When a list item is clicked and the details are shown, I call pushState to add a history item. When clicking on my “back” button, I call history.back() to return. By handling the popstate event, I do the same when the browser’s back navigation button is used.

Now the trouble starts. Here, the user can click the browser’s “forward” button. I’d expect another popstate event to be triggered, but I see a full page load instead. On the newly loaded page, then the expected popstate event is triggered, but that’s too late.

The page transitions use animations and they only work if no reload happens in between. Also, loading the page newly destroys any view state.

How can I prevent the browser from loading the page when clicking the browser’s forward button?

Using Firefox 132 on Windows. ChatGPT was repeating the same information as MDN, but at some point stated that a full page load would be normal on forward navigation. Wouldn’t that contradict the whole purpose of a “soft navigation” with the history API? If that’s true, can it be prevented?

Also, I’m having trouble detecting whether the popstate was raised from a back or forward navigation. A few hacks seem to exist but they all fail after looking at them for more than a few seconds. For example, the user can skip history entries, which none of the solutions even try to handle. I’m thinking about dropping the whole history API completely and not allowing the user the use the back button at all within my SPA because it’s so broken and useless.

An acceptable hack would be to clear all future history on any popstate event to ensure that the user can only ever use it to go back but never forward again. But sadly the history API hides behind “security issues” and won’t even offer that simple operation. (I could erase all future history by calling pushState again, but that would introduce a new unwanted entry and mess up the history when going back next time.)

I’m not using any JavaScript framework or library, but would look at a good implementation to see how it might be solved.