Categories
Javascript Tech

How to Print Long Item Names Correctly on an 80mm Thermal Printer with JavaScript

Printing receipts from a web application looks simple until you encounter a menu item with a long name.

A short item may print perfectly:

Butter Pav Bhaji       x1 ₹150

But a longer item can easily break an 80mm thermal receipt:

Paneer Cheese Pav Bhaji - Regular x1 ₹210

The quantity or price may move outside the printable area, text may be clipped, or the printer may wrap the line at an unexpected position.

I encountered this while generating a Kitchen Order Ticket (KOT) using JavaScript and browser printing.

The solution was not to reduce the font size or truncate menu item names.

Instead, I created a small fixed-width text formatter that:

  • wraps long item names automatically
  • avoids cutting words where possible
  • keeps quantity and price visible
  • keeps the total amount right-aligned
  • supports preparation options and notes
  • prints consistently on an 80mm thermal printer

Here’s how it works.


The Original Problem

The initial formatter was straightforward:

const LINE_WIDTH = 32;

const formatItem = (item: any) => {
    const total = item.price * item.qty;

    const left = `${item.name} x${item.qty}`;
    const right = `₹${total}`;

    const spacing =
        LINE_WIDTH - left.length - right.length;

    return (
        left +
        " ".repeat(Math.max(1, spacing)) +
        right
    );
};

For short menu items, this works well:

Butter Pav Bhaji       x1 ₹150

The formatter calculates the space between the item description and price and inserts enough spaces to align the amount.

The problem starts when the item name becomes longer than the available width.

For example:

Paneer Cheese Pav Bhaji - Regular x1 ₹210

There is no longer enough space for the item name, quantity, and price on the same line.

The calculation:

LINE_WIDTH - left.length - right.length

becomes negative.

Using:

Math.max(1, spacing)

prevents an invalid number of spaces, but it doesn’t solve the real problem: the text itself is too long for the receipt.


Why 80mm Thermal Printing Needs Special Handling

An 80mm paper roll does not necessarily provide 80mm of usable text space.

The actual printable area depends on several factors:

  • printer hardware margins
  • printer driver settings
  • browser print scaling
  • CSS padding
  • font family
  • font size
  • operating system print settings

For plain-text thermal printing, using a monospace font with a predictable character width makes formatting much easier.

In this example, I use:

const LINE_WIDTH = 32;

Thirty-two characters is deliberately conservative.

Some 80mm printers can fit more characters per line, but using a slightly smaller width makes the receipt more reliable across different printers and browser print configurations.


Step 1: Create Basic Receipt Helpers

First, define the receipt width and helpers for separators and centered text.

const LINE_WIDTH = 32;

const line = () => "-".repeat(LINE_WIDTH);

const center = (text: string) => {
    if (!text) return "";

    const space = Math.max(
        0,
        Math.floor(
            (LINE_WIDTH - text.length) / 2
        )
    );

    return " ".repeat(space) + text;
};

Now:

line();

produces:

--------------------------------

And:

center("SELF PICKUP");

produces approximately:

          SELF PICKUP

Because a monospace font is used later, each space has a predictable width.


Step 2: Create a Reusable Text-Wrapping Function

Next, we need a utility that can wrap long strings without cutting normal words in the middle.

const wrapText = (
    text: string,
    width: number
): string[] => {
    if (!text) return [];

    const words = text
        .trim()
        .split(/\s+/);

    const lines: string[] = [];

    let current = "";

    words.forEach((word) => {
        /*
         * Handle an individual word that is
         * longer than the entire available width.
         */
        if (word.length > width) {
            if (current) {
                lines.push(current);
                current = "";
            }

            for (
                let i = 0;
                i < word.length;
                i += width
            ) {
                lines.push(
                    word.slice(i, i + width)
                );
            }

            return;
        }

        const next = current
            ? `${current} ${word}`
            : word;

        if (next.length <= width) {
            current = next;
        } else {
            if (current) {
                lines.push(current);
            }

            current = word;
        }
    });

    if (current) {
        lines.push(current);
    }

    return lines;
};

For example:

wrapText(
    "Paneer Cheese Masala Pav Bhaji Regular",
    20
);

can produce:

Paneer Cheese Masala
Pav Bhaji Regular

Instead of:

Paneer Cheese Masala P
av Bhaji Regular

This makes printed receipts significantly easier to read.


Step 3: Format the Item While Reserving Space for Quantity and Price

The important part is that the item description should be flexible, while the quantity and price should remain readable.

For example, we want:

Paneer Cheese Pav    x3 ₹630
Bhaji

rather than:

Paneer Cheese Pav Bhaji x3 ₹
630

We can accomplish this by calculating how much space the metadata requires first.

const formatItem = (item: any) => {
    const qty = Number(
        item.qty || 0
    );

    const price = Number(
        item.price || 0
    );

    const total = price * qty;

    const name = String(
        item.name || ""
    ).trim();

    const meta = `x${qty} ₹${total}`;

    /*
     * Reserve enough room on the first
     * line for quantity and price.
     */
    const availableWidth = Math.max(
        10,
        LINE_WIDTH - meta.length - 1
    );

    const words = name.split(/\s+/);

    let firstLine = "";

    const remainingWords: string[] = [];

    for (
        let index = 0;
        index < words.length;
        index++
    ) {
        const word = words[index];

        const candidate = firstLine
            ? `${firstLine} ${word}`
            : word;

        if (
            candidate.length <=
            availableWidth
        ) {
            firstLine = candidate;
        } else {
            remainingWords.push(
                ...words.slice(index)
            );

            break;
        }
    }

    /*
     * Handle an unusually long first word.
     */
    if (
        !firstLine &&
        remainingWords.length
    ) {
        const word =
            remainingWords.shift()!;

        firstLine = word.slice(
            0,
            availableWidth
        );

        if (
            word.length >
            availableWidth
        ) {
            remainingWords.unshift(
                word.slice(
                    availableWidth
                )
            );
        }
    }

    /*
     * Calculate spacing between the item
     * description and quantity/price.
     */
    const spacing = Math.max(
        1,
        LINE_WIDTH -
            firstLine.length -
            meta.length
    );

    const output = [
        `${firstLine}${" ".repeat(
            spacing
        )}${meta}`,
    ];

    /*
     * Remaining item description can use
     * the entire width of subsequent lines.
     */
    if (remainingWords.length) {
        output.push(
            ...wrapText(
                remainingWords.join(" "),
                LINE_WIDTH
            )
        );
    }

    return output.join("\n");
};

Now long item names wrap without pushing the price outside the receipt.

For example:

Paneer Cheese Pav    x3 ₹630
Bhaji

Another item might produce:

Paneer Cheese Masala x1 ₹210
Pav Bhaji - Regular

And an even longer item remains safe:

Paneer Tikka Butter  x2 ₹640
Masala Special Family Size
with Extra Cheese

Step 4: Support Preparation Options and Notes

Kitchen tickets often contain more than the product name.

For example:

Paneer Butter Pav    x1 ₹190
Bhaji
  No Onion, Less Oil
  Note: Extra spicy

You can build the items section like this:

const itemsBlock = cart
    .map((item: any) =>
        [
            formatItem(item),

            item.prepOptions?.length
                ? "  " +
                  item.prepOptions.join(", ")
                : "",

            item.note
                ? "  Note: " + item.note
                : "",
        ]
            .filter(Boolean)
            .join("\n")
    )
    .join("\n");

This keeps additional kitchen instructions underneath their corresponding item.


Step 5: Right-Align the Total Amount

The same fixed-width technique can also create a cleaner total row.

Instead of:

TOTAL: ₹1710.00

we can print:

TOTAL:                  ₹1710.00

Create another formatter:

const formatTotal = (
    total: number | string
) => {
    const left = "TOTAL:";
    const right = `₹${total}`;

    const spacing = Math.max(
        1,
        LINE_WIDTH -
            left.length -
            right.length
    );

    return (
        left +
        " ".repeat(spacing) +
        right
    );
};

Then use:

formatTotal(total);

The result is:

--------------------------------
TOTAL:                  ₹1710.00
--------------------------------

This makes totals much easier to identify on a printed receipt.


Step 6: Build the Complete KOT

Here is a simplified version of the receipt builder.

This example uses dayjs for the timestamp.

View Complete Source Code section below in this page.


Step 7: Configure Browser Printing for 80mm Paper

Formatting the text correctly is only half of the solution.

The browser also needs to know that the output is intended for an 80mm thermal printer.

First, create a small HTML escape function.

const escapeHtml = (
    value: string
) => {
    return value
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
};

Escaping the receipt is important because item names, customer information, notes, and other values may contain characters that would otherwise be interpreted as HTML.

Then create the print function:

export const printReceipt = (
    text: string
) => {
    const printWindow =
        window.open("", "_blank");

    if (!printWindow) return;

    printWindow.document.write(`
        <!DOCTYPE html>

        <html>
            <head>
                <title>KOT</title>

                <style>
                    @page {
                        size: 80mm auto;
                        margin: 0;
                    }

                    * {
                        box-sizing: border-box;
                    }

                    html,
                    body {
                        margin: 0;
                        padding: 0;
                        width: 80mm;
                        background: #fff;
                    }

                    pre {
                        margin: 0;
                        padding: 4mm 3mm;
                        width: 80mm;

                        font-family:
                            "Courier New",
                            Courier,
                            monospace;

                        font-size: 12px;
                        line-height: 1.35;

                        white-space: pre-wrap;
                        overflow-wrap: break-word;

                        color: #000;
                    }

                    @media print {
                        html,
                        body {
                            width: 80mm;
                        }

                        pre {
                            width: 80mm;
                        }
                    }
                </style>
            </head>

            <body>
                <pre>${escapeHtml(text)}</pre>
            </body>
        </html>
    `);

    printWindow.document.close();

    printWindow.focus();

    setTimeout(() => {
        printWindow.print();
    }, 100);
};

The important CSS is:

@page {
    size: 80mm auto;
    margin: 0;
}

combined with:

font-family:
    "Courier New",
    Courier,
    monospace;

A monospace font is particularly important because the JavaScript formatter relies on characters having approximately equal visual widths.


Printing the KOT

Once the formatter and print function are ready, printing becomes straightforward:

const handlePrint = () => {
    if (!cart?.length) return;

    const text =
        buildThermalPrint({
            cart,
            customer,
            orderType,
            store,
            receiptNo,
        });

    printReceipt(text);
};

You can then connect it to a button:

<button
    type="button"
    onClick={handlePrint}
>
    Print KOT
</button>

Final Output

The resulting KOT can look like this:

         MY STORE Kitchen
--------------------------------
KOT No: 1790400901271
Date: 26/09/2026 11:05 AM
--------------------------------
          SELF PICKUP
--------------------------------
Paneer Cheese Pav    x3 ₹630
Bhaji - Regular

Paneer Butter Pav    x3 ₹570
Bhaji - Regular

Cheese Butter Pav    x1 ₹190
Bhaji - Regular

Paneer Cheese Masala x1 ₹210
Pav Bhaji - Regular

Butter Schezwan      x1 ₹110
Masala Dosa - Regular
--------------------------------
TOTAL:                  ₹1710.00
--------------------------------
Name: Guest Customer
Phone: 9876543210
--------------------------------
           Thank You

Long menu item names no longer push the quantity or price outside the receipt width.

The receipt also remains plain text, which makes it lightweight and suitable for thermal printing.


Why Not Just Use CSS word-wrap?

You could allow the browser to automatically wrap everything:

white-space: pre-wrap;
overflow-wrap: break-word;

But that alone doesn’t understand the structure of a receipt.

The browser might produce something like:

Paneer Cheese Pav Bhaji - Regular x3
₹630

or:

Paneer Cheese Pav Bhaji -
Regular x3 ₹630

That may technically fit, but it gives you less control over the kitchen ticket layout.

By formatting the text before printing, we explicitly tell the receipt:

  1. how wide a line can be
  2. where the item description should wrap
  3. where quantity should appear
  4. where price should appear
  5. how totals should align

CSS then handles the physical 80mm page.

The two approaches work together.


Why Use Plain Text Instead of an HTML Table?

HTML tables and CSS Grid can also produce excellent receipts.

However, plain-text formatting has some useful properties for thermal printing:

  • simple output
  • predictable layout
  • easy debugging
  • minimal CSS
  • easy copying and logging
  • works naturally with monospace printers
  • straightforward alignment

For more sophisticated receipts containing logos, multiple columns, QR codes, taxes, discounts, or complex invoice structures, an HTML-based layout may be preferable.

For a KOT, however, fixed-width text can be an effective solution.


Important: Character Width Is Not Physical Width

One thing to keep in mind is that:

const LINE_WIDTH = 32;

does not mean every 80mm printer can only print 32 characters.

Depending on the printer, font, DPI, and driver configuration, you may be able to use:

32
40
42

or even:

48

characters per line.

Start conservatively and test with the actual thermal printer.

For example:

const LINE_WIDTH = 32;

is safer than increasing the width until the text is almost touching both edges of the paper.

A small amount of unused horizontal space is usually preferable to clipped kitchen tickets.


Browser Printing Has Limitations

This implementation uses:

window.print();

That means the browser and operating system still control the final print process.

Depending on the environment, users may still need to select:

  • the correct thermal printer
  • 80mm paper size
  • appropriate margins
  • 100% print scale
  • header/footer disabled

For a web-based POS or restaurant ordering system, this approach works well when manual browser printing is acceptable.

If completely silent printing is required, a dedicated local printing solution or printer integration may eventually be necessary.


Final Thoughts

The key lesson is that thermal receipt formatting should not depend entirely on the browser deciding where text should wrap.

For a predictable 80mm KOT:

  1. use a monospace font
  2. define a maximum character width
  3. reserve space for quantity and price
  4. wrap long item names yourself
  5. right-align important numeric values
  6. explicitly configure the 80mm print page
  7. test against the physical printer

Instead of shrinking fonts or truncating menu item names, this approach lets the content naturally expand vertically while keeping the receipt width predictable.

That is usually exactly what you want from a thermal Kitchen Order Ticket.


Complete Source Code

The complete TypeScript implementation is available here:

View the 80mm Thermal KOT Printing Code → Coming soon this page.


Frequently Asked Questions

What line width should I use for an 80mm thermal printer?

There is no universal character count because it depends on the printer, font size, driver, and margins.

A value such as:

const LINE_WIDTH = 32;

is a conservative starting point.

Test the result using the actual printer before increasing it.

Why should I use a monospace font?

The formatter aligns content by counting characters and inserting spaces.

With a proportional font, characters have different visual widths, so:

TOTAL:                  ₹1710.00

may not align correctly.

A monospace font gives every character approximately the same width.

Can this work with a 58mm thermal printer?

Yes.

The same formatter can be used, but LINE_WIDTH, font size, and CSS width should be adjusted for the smaller paper size.

For example, you might start with a smaller line width and:

@page {
    size: 58mm auto;
}

The exact configuration should be tested against the target printer.

Can I print preparation options and kitchen notes?

Yes.

Because additional information is printed underneath the item, modifiers fit naturally:

Paneer Butter Pav    x1 ₹190
Bhaji
  No Onion, Less Oil
  Note: Extra spicy

This makes the same approach particularly useful for restaurant KOT printing.

Should I truncate long menu item names?

Usually, no.

For kitchen tickets, the full item name can be operationally important.

Allowing the description to wrap onto another line is generally safer than hiding part of the item name just to maintain a single-line layout.


If you’re building a restaurant POS, ordering application, or any web application that needs thermal printing, this fixed-width formatting approach provides a simple foundation that can later be extended for taxes, discounts, order numbers, QR codes, modifiers, and other receipt information.

Categories
Learning

Finding the ending number: What is 60% of 25?

Formula: Multiply the percentage by the total value

.60 x 25 = 15

Categories
Learning Learning Tech

Laravel getting error: Target class [App\Http\Controllers\GurbaniReadingController::class] does not exist. But file already exists!!

Hello Guys,

Facing this issue and struggling to find the cause?, okay then lets direct jump in to the fix I found or more precisely mistake I found!

In picture you might seeing controller name is different than I have mentioned below; I am changed it to Book, so don’t get confuse.

In my case I was wrapped the loading on controller in web.php route with single quotes!

Line of code causing this error:

Route::get('/book-readings/upload-photos', ['App\Http\Controllers\BookReadingController::class', 'uploadPhotos']);

Very carefully watch in above code code was wrapped in quotes: ‘App\Http\Controllers\BookReadingController::class’,
Controller should be loaded without single quotes;

And second important reason is it, this line should shall fall before the resource route if you have similar to this controller, in my case it was :

Route::resource('/book-readings', App\Http\Controllers\BookReadingController::class); 
// this line was defined before the above route I wanted to work! (I am not sure why this line causing to stop showing the page :/)

Finally I make these changes so everything started working smoothly & all routes loading fine and up!.

// Upload Audio Files:
Route::get('/book-readings/upload-photos', [App\Http\Controllers\BookReadingController::class, 'showPhotos'])->name('book-readings.upload-photos');
Route::post('/book-readings/upload-photos', [App\Http\Controllers\BookReadingController::class, 'uploadPhotos']);
Route::delete('/book-readings/upload-photos/{id}', [App\Http\Controllers\BookReadingController::class, 'destroyPhoto']);

Route::resource('/book-readings', App\Http\Controllers\BookReadingController::class);

Hope this will give you a hint to point the issue you might come up like this mostly when we are new and learning and developing new things!

Happy Learnings

Categories
Javascript Learning

How to fix Uncaught TypeError: Cannot assign to read only property ‘0’ of object occurring in JavaScript?

Hello,

This type error mostly get in scenario when you try to sort the readyonly data array.

For me this was occoured when I tried to sort the direct result from my GraphQL query response data like below:

const sortedData = data.bhangarwalas.sort((a, b) => a?.firstname > b?.firstname ? 1 : -1);

In above, data.bhangarwalas is graphql query response results which is readonly in nature as response.

To fix this issue the solution is quick fix for which I have too google to know the result!

Error Screenshot Uncaught TypeError: Cannot assign to read only property ‘0’ of object ‘[object Array]’

Here is the quick solution:

const sortedData = [...data.bhangarwalas];
      sortedData.sort((a, b) => a?.firstname > b?.firstname ? 1 : -1);

In code above, We need to clone or you in other words, copying the “data.bhangarwalas” into new array variable and then over that variable, we need to perform sorting operation, which results us right response.

Hope this help you to solve the quick error or to know what scenario this type of error is generated.

Thanks for reading.

Happy learning!

Categories
Javascript Tech

What is Event Loop & Micro and Macro Tasks in JavaScript?

Hello,

The basic concept behind the event loop working in Javascript engine!

Event Loop is a mechanism in JavaScript that handles asynchronous tasks in a non-blocking way. When JavaScript code is executed, it is run inside an event loop, which continuously checks if there are any tasks to be executed in the queue. The event loop is responsible for running the tasks in the queue, and it does this in a specific order.

The Event Loop in JavaScript has two main components: the Call Stack and the Callback Queue. The Call Stack is responsible for keeping track of the execution of the synchronous code. When a function is called, it is added to the top of the call stack, and when the function returns, it is removed from the top of the call stack.

The Callback Queue, on the other hand, is responsible for keeping track of the asynchronous tasks. When an asynchronous task is completed, it is added to the Callback Queue. The event loop continuously checks the Callback Queue to see if there are any tasks that can be executed. If there is a task, it is moved to the Call Stack, where it is executed.

Microtasks and Macrotasks are two types of tasks in JavaScript that are executed by the event loop.

Microtasks are tasks that are executed immediately after the current task has completed. Microtasks are executed before the next rendering of the web page, which means that they have a higher priority than Macrotasks. Some examples of Microtasks include Promises, MutationObserver, and process.nextTick in Node.js.

Macrotasks, on the other hand, are tasks that are executed after all the Microtasks have been executed. Macrotasks include tasks such as setTimeout, setInterval, and I/O operations in Node.js.

In summary, the Event Loop in JavaScript is responsible for handling asynchronous tasks in a non-blocking way. The Event Loop has two main components, the Call Stack and the Callback Queue. Microtasks and Macrotasks are two types of tasks that are executed by the event loop, and they have different priorities. Microtasks are executed before Macrotasks and are used for tasks that need to be executed immediately after the current task has completed, while Macrotasks are used for tasks that can be executed at a later time.

Source: AI Interaction Channels

Happy Learning!

Categories
Javascript Tech

How to identify closed 5km range co ordinates from given co ordinates

Hello,

This nice question and other below I have learned recently! Let see how its answered.

To identify the closed 5km range coordinates from a given set of coordinates, you need to first calculate the difference in latitude and longitude between the given coordinates and find the minimum and maximum values.

Here’s the basic formula:

Latitude range:

  • min latitude = given latitude – (5 / 111.2)
  • max latitude = given latitude + (5 / 111.2)

Longitude range:

  • min longitude = given longitude – (5 / (111.2 * cos(given latitude)))
  • max longitude = given longitude + (5 / (111.2 * cos(given latitude)))

Note: In the above formula, (5 / 111.2) is used to convert 5km to degrees. The value of 111.2 is the approximate number of km per degree of latitude. The value of (111.2 * cos(given latitude)) is used to convert 5km to degrees of longitude.

Once you have calculated the minimum and maximum values of latitude and longitude, you can create a bounding box by combining them. The coordinates within this bounding box would be considered as closed within a 5km range of the given coordinates.

Can you tell me more on last results?

Sure! The last results I mentioned are the coordinates of a bounding box that defines a closed area within a 5km range of a given set of coordinates.

A bounding box is a rectangular area that encloses a set of points or coordinates. In this case, the bounding box encloses the coordinates that are within a 5km range of the given coordinates. The minimum and maximum latitude and longitude values that were calculated earlier define the boundaries of this bounding box.

By combining the minimum and maximum latitude and longitude values, you get a rectangular area that encloses all the coordinates that are within a 5km range of the given coordinates. Any coordinate that lies within this rectangular area can be considered to be within a 5km range of the given coordinates.

This information can be useful in various applications, such as mapping, geolocation-based services, or location-based searches. For example, if you want to search for all the restaurants within a 5km range of a given location, you can use the bounding box coordinates to filter out the restaurants that are outside the 5km range.

Can you tell me more with example for bounding box calculations?

Sure, here’s an example of how you can calculate the bounding box coordinates for a given set of coordinates within a 5km range.

Let’s assume that the given coordinates are:

Latitude: 37.7749 Longitude: -122.4194

To calculate the bounding box coordinates:

  1. Calculate the minimum and maximum latitude:
  • min latitude = 37.7749 – (5 / 111.2) = 37.7692
  • max latitude = 37.7749 + (5 / 111.2) = 37.7807
  1. Calculate the minimum and maximum longitude:
  • min longitude = -122.4194 – (5 / (111.2 * cos(37.7749))) = -122.4257
  • max longitude = -122.4194 + (5 / (111.2 * cos(37.7749))) = -122.4131

So, the bounding box coordinates would be:

min latitude: 37.7692 min longitude: -122.4257 max latitude: 37.7807 max longitude: -122.4131

This means that any coordinate that lies within the rectangular area defined by these bounding box coordinates would be considered to be within a 5km range of the given coordinates (37.7749, -122.4194).

Well hope you understand from the given formulation and examples how can create a boundingbox for the range we need to search in for against our given co-ordinates, lets deep in further how we can implement and take this up with our Javascript Skills!

Nice, how I we can use this in Javascript?

Here’s an example of how you can calculate the bounding box coordinates for a given set of coordinates within a 5km range using JavaScript:

function getBoundingBox(lat, lng, distance) {
  const RADIUS_OF_EARTH_KM = 6371;
  const latRadian = lat * (Math.PI / 180);
  const degLatKm = RADIUS_OF_EARTH_KM * Math.cos(latRadian);
  const degLonKm = RADIUS_OF_EARTH_KM;
  const latDegree = distance / degLatKm;
  const lngDegree = distance / degLonKm;

  return {
    minLat: lat - latDegree,
    minLng: lng - lngDegree,
    maxLat: lat + latDegree,
    maxLng: lng + lngDegree
  };
}

const coordinates = { lat: 37.7749, lng: -122.4194 };
const boundingBox = getBoundingBox(coordinates.lat, coordinates.lng, 5);

console.log(boundingBox);

In this example, the getBoundingBox function takes the latitude, longitude, and distance as input parameters. The distance is the radius of the bounding box and is specified in kilometers. The function first converts the latitude and longitude to radians and calculates the number of kilometers per degree of latitude and longitude. The minimum and maximum latitude and longitude values are then calculated using these values and the given distance. Finally, the bounding box coordinates are returned as an object.

Nice, How to I use the bounding box with real test case example?

Here’s an example of how you could use the bounding box coordinates with a real-world test case. Let’s say you have a list of restaurants and their coordinates, and you want to search for all the restaurants within a 5km range of a given location.

const restaurants = [
  { name: "Restaurant A", lat: 37.7820, lng: -122.4464 },
  { name: "Restaurant B", lat: 37.7696, lng: -122.4138 },
  { name: "Restaurant C", lat: 37.7816, lng: -122.4140 },
  { name: "Restaurant D", lat: 37.7711, lng: -122.4336 },
  { name: "Restaurant E", lat: 37.7634, lng: -122.4359 },
];

const searchLocation = { lat: 37.7749, lng: -122.4194 };
const searchRadius = 5;
const boundingBox = getBoundingBox(searchLocation.lat, searchLocation.lng, searchRadius);

const filteredRestaurants = restaurants.filter(restaurant => {
  return (
    restaurant.lat >= boundingBox.minLat &&
    restaurant.lat <= boundingBox.maxLat &&
    restaurant.lng >= boundingBox.minLng &&
    restaurant.lng <= boundingBox.maxLng
  );
});

console.log(filteredRestaurants);

In this example, the restaurants array contains the list of restaurants and their coordinates. The searchLocation object contains the location for which you want to search the restaurants. The searchRadius specifies the radius of the search in kilometers.

The boundingBox is calculated using the getBoundingBox function, as shown in the previous example. The filteredRestaurants array is then created by filtering the restaurants array based on whether their coordinates fall within the bounding box or not. Finally, the filtered restaurants are logged to the console.

Hope this give us nice insight for the questions we have and need to develop as we develop advance things.

Source: Some AI Interaction Channels

Happy Learning!

Categories
Javascript Tech

Closures in JavaScript

A closure in JavaScript is a function that has access to variables in its outer scope, even after the outer function has returned. A closure is created when a function is defined inside another function and the inner function references variables in the outer function’s scope.

Closures allow you to preserve the state of a function’s variables even after the function has returned, and they can be used to create powerful and flexible functions that can be reused in different parts of your code.

Here’s a simple example of a closure in JavaScript:

function outerFunction(x) {
return function innerFunction(y) {
return x + y;
}
}

const add5 = outerFunction(5);
console.log(add5(3)); // 8

In this example, the outerFunction returns the innerFunction, which has access to the x variable in its outer scope. When we call outerFunction(5), it returns the innerFunction with x set to 5, and we assign it to the add5 variable. When we later call add5(3), it returns the result of x + y, which is 8.

Closures are an important concept in JavaScript, as they can be used to create functions that have private variables, to implement object-oriented concepts like classes and prototypes, and to manage state and data in complex applications.

Source: AI Interaction Channel

Happy Learning!

Categories
Javascript Learning Tech

How to filter customers state array based on set of array of ids in javascript/reactjs.

Filtering customers state array based on array of ids in javascscript/react.

const activeCustomerIdSet = [3,4,9];

//customers is array of customer data in my case its array value is bit different, just to note.

const filteredActiveCustomersIds = Array.from(activeCustomerIdSet) || [];
            let nonActiveCustomers = [];
            let filterCustomer = [...customers];
            if (filteredActiveCustomersIds.length) {
                for (let cid of filteredActiveCustomersIds) {
                    filterCustomer = filterCustomer?.filter(cust => {
                        if (+cust?.value?.id !== cid) {
                            
                            return cust;
                        }
                    });
                }
                nonActiveCustomers = [...nonActiveCustomers,
                    filterCustomer];
            }

            console.log({  filteredActiveCustomersIds, customers, nonActiveCustomers });

Hope you find useful in your search!

Keeping it short simple and straight.

Happy coding!

Categories
Blog Javascript Learning

Easy steps to create source endpoints with base url’s in react or any spa applications using ES6 tagged templates as a project utility and maintainbilty

Hello,

Here I would like to share with you a very handy and new innovative approach using ES6 Tag Literals template to ease of creating the base URL’s for use a single source of truth defined as library constants or utility code to refer as the single page application grows.

Let’s get hand dirty and mind free from hassle of maintaining and forming lines cluttered code and creating mess in many files as web application grows.

Hope you understand what I mean, developers get frustrated to follow the best practice as in tight project deadlines,

Heads up on I am currently using 2Factor.in endpoints in this post as I were using part of the project implementation, we will head in list out numbers as steps needs to follow for the quick implementation:

  1. We will save API key and API base URL in env file, (hope you are aware were it will lies in your project code, basically it lies at the core level of project director with named and with extension exactly, .env
SITE_2FACTORIN_API_BASE_URL=https://2factor.in/API/V1/
SITE_2FACTORIN_API_KEY=XXXXXX-dde0-23ec-XXXXXXXXXX

2. As I were using Nextjs, so I need to configure these env variables in next.config.js file to export it to the FE side contants(.js) file:

//next.config.js
module.exports = {
  publicRuntimeConfig: {
    SITE_2FACTORIN_API_BASE_URL: process.env.SITE_2FACTORIN_API_BASE_URL,
    SITE_2FACTORIN_API_KEY: process.env.SITE_2FACTORIN_API_KEY,
  },
};

3. Next we need to import publicRuntimeConfig object in our constants(.js) file

import { publicRuntimeConfig } from "./env.settings";

I am importing from .env.settings files which is actually using nextjs getConfig method to export publicRuntimeConfig variable, I am skipping that step to show here, once you search for docs on next/config you will get an idea what we are doing here.

4. Main part here it comes in contants.js file:

export const f2param1 = (param) => param || 1234657890;
export const f2param2 = (param) => param || "myTemplateName-OTP";

export function tagTemplate2FactorAPI(strings, param1, param2) {

  const { SITE_2FACTORIN_API_BASE_URL, SITE_2FACTORIN_API_KEY } = publicRuntimeConfig;
  const prefixBaseUrl = SITE_2FACTORIN_API_BASE_URL + SITE_2FACTORIN_API_KEY + '/';

  let str0 = strings[0] || ""; // "That "
  let str1 = strings[1] || ""; // " is a "
  let str2 = strings[2] || ""; // "."

  // We can even return a string built using a template literal
  return `${prefixBaseUrl}${str0}${param1 || ''}${str1}${param2 || ''}${str2}`;
}

export const factor2API_Endpoint = {
  CHECK_OTP_SMS_BALANCE: `BAL/SMS`,
  SEND_OTP_SMS: tagTemplate2FactorAPI`SMS/${f2param1()}/AUTOGEN`,
  SEND_OTP_SMS_TEMPLATE: tagTemplate2FactorAPI`SMS/${f2param1()}/AUTOGEN/${f2param2()}`,
  SEND_VERIFY_SMS: tagTemplate2FactorAPI`SMS/VERIFY/${f2param1()}/${f2param2()}`,
  CHECK_TRANS_SMS_BALANCE: `/ADDON_SERVICES/BAL/TRANSACTIONAL_SMS`,
  SEND_TRANS_SMS: `/ADDON_SERVICES/SEND/TSMS`,
  SEND_TRANS_SMS_DYNAMIC_TEMPLATE: `/ADDON_SERVICES/SEND/TSMS`,
};

console.log(factor2API_Endpoint.SEND_OTP_SMS);
console.log(factor2API_Endpoint.SEND_OTP_SMS_TEMPLATE);
console.log(factor2API_Endpoint.SEND_VERIFY_SMS);

This is how the final code looks, but there is a catch in this code, just need to handle of passing the params dynamically to the constants property of the object, otherwise with the fixed 2 params in same file would do the trick.

Will share once I got the way of passing dynamic params values to object property in template literal invocation line.

—— Here I found it the other approach —- Edited: 00:44 (after few mins of publishing this post after above approach shared 🙂 )

export function tagTemplate2FactorAPI(strings, ...keys) {

  const { SITE_2FACTORIN_API_BASE_URL, SITE_2FACTORIN_API_KEY } = publicRuntimeConfig;
  const prefixBaseUrl = SITE_2FACTORIN_API_BASE_URL + SITE_2FACTORIN_API_KEY + '/';

  return (function (...values) {
    let dict = values[values.length - 1] || {};
    let result = [strings[0]];
    keys.forEach(function (key, i) {
      let value = Number.isInteger(key) ? values[key] : dict[key];
      result.push(value, strings[i + 1]);
    });

    result.unshift(prefixBaseUrl); //added this line to prefix with base url path
    return result.join('');
  });
}

export const factor2API_Endpoint = {
  CHECK_OTP_SMS_BALANCE: `BAL/SMS`,
  SEND_OTP_SMS: tagTemplate2FactorAPI`SMS/${0}/AUTOGEN`,
  SEND_OTP_SMS_TEMPLATE: tagTemplate2FactorAPI`SMS/${0}/AUTOGEN/${1}`,
  SEND_VERIFY_SMS: tagTemplate2FactorAPI`SMS/VERIFY/${0}/${1}`,
  CHECK_TRANS_SMS_BALANCE: `/ADDON_SERVICES/BAL/TRANSACTIONAL_SMS`,
  SEND_TRANS_SMS: `/ADDON_SERVICES/SEND/TSMS`,
  SEND_TRANS_SMS_DYNAMIC_TEMPLATE: `/ADDON_SERVICES/SEND/TSMS`,
};

 console.log(factor2API_Endpoint.SEND_OTP_SMS(12311312, 'newTemplate-newOTP'));
 console.log(factor2API_Endpoint.SEND_OTP_SMS_TEMPLATE(5656565, 'newTemplate-newOTP'));
 console.log(factor2API_Endpoint.SEND_VERIFY_SMS(456646545, 'newTemplate-newOTP'));

Output log of the above code:

Solution, I found right after reading the basic guide on Tagged template on Mozilla documentation on Tagged Templates

Thanks for reading.

Happy Learning.