Loop through an API response in next js

I am currently working on a project where I need to print some labels with a button click. However, the labels can only be printed if certain requirements are fulfilled.

First, my user gets to a ShadCn dialog where they can check some checkboxes. The checkboxes then send a request to a function called checkFulfilled (which will be shown further down). That function checks if an item is fulfilled in the order or not. If it isn’t, it sends a POST request to fulfill it. Then, from that function, I pass information to another function called createSale that is needed to book the shipment and mark the fulfillment status in the API. Without that fulfilled status, the label cannot be printed.

Now comes the interesting part. When the order is fulfilled, the API will return the whole order, but only one part of the order is important—that is called order_fulfillments, which can have between 2 to 1000 arrays in it. Every array in the order_fulfillments has a so-called shipment_id, but only one of the shipment_ids is not null. I need to loop through all the shipment IDs before I can print the label because the printLabel API requires me to send in the shipment_id.

The problem: Right now, when I try to print the label, even when everything else has passed successfully, I get this error message: “shipmentId is null, not calling PrintLabel.” Can someone explain how I can solve the problem?

The code:

Dialog component where all frontend interaction happen

import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogHeader,
    DialogTitle,
    DialogTrigger,
} from "@/components/ui/dialog";
import { Separator } from "@/components/ui/separator";
import {
    Card,
    CardContent,
    CardDescription,
    CardFooter,
    CardHeader,
    CardTitle,
} from "@/components/ui/card";
import { Package } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Orders } from "@/lib/types/shipmondo";
import { FurfillOrder, PrintLabel, cancel, createSale, findId, putStatus } from "./actions";
import { Product } from "@/lib/types/wix";
import { Button } from "@/components/ui/button";
import { Progress } from "@/components/ui/progress";
import { Checkbox } from "@/components/ui/checkbox";
import { CircleX } from "lucide-react";
import { string } from "zod";

export default function Dialogt({ order, totalWeight, products }: { order: Orders, totalWeight: number, products: Product[] }) {
    const router = useRouter();
    // const [isOpen, setIsOpen] = useState(true);
    const [checkedItems, setCheckedItems] = useState<number[]>([]);
    const [isPacking, setIsPacking] = useState(false);

    const furfillOrder = async (item_id: string, order_id: string, order: Orders, item_quantity: Number) => {
        await FurfillOrder(item_id, order_id, item_quantity);
    }

    const handleCheckboxChange = (index: number, item_id: string, order_id: string, item_quantity: Number) => {
        setCheckedItems(prevCheckedItems =>
            prevCheckedItems.includes(index)
                ? prevCheckedItems.filter(item => item !== index)
                : [...prevCheckedItems, index]
        );
        furfillOrder(item_id, order_id, order, item_quantity);
    };

    const calculateProgress = () => {
        return (checkedItems.length / order.order_lines.length) * 100;
    };

    // const packad = async (order_id: string) => {
    //     await putStatus(order_id);
    //     setIsPacking(true);
    // };

    // const handleClose = () => {
    //     setIsOpen(false);
    // };

    // const cancelOrder = async (order_id: string) => {
    //     await cancel(order_id);
    //     handleClose();
    // };

    const print = async (order_id: any) => {
        await PrintLabel(order_id);

    }

    const ida = async (order_id: string) =>{
        await findId(order_id)
    }
    useEffect(() => {
        if (isPacking) {
            router.push('/packning/packas');
        }
    }, [isPacking, router]);




    return (
        <Dialog>
            <DialogTrigger>
                <Package size={25} />
            </DialogTrigger>
            <DialogContent className={'g:max-w-screen-lg overflow-y-scroll max-h-screen'}>
                <DialogHeader>
                    <DialogTitle className="items-center flex justify-around">
                        Order {order.order_id.substring(0, 12)}
                        {/* {order.order_status === "on_hold" ? <Badge className="bg-[#ffA500] text-black">Påbörjad</Badge> : <Button onClick={() => packad(order.id)}>Packa</Button>}
                        {order.order_status === 'on_hold' ? <Button
                            onClick={() => cancelOrder(order.id)}
                            variant={'ghost'} color={'destructive'}>Avbryt
                        </Button> : ''} */}
                    </DialogTitle>
                </DialogHeader>
                <DialogDescription>
                    <Card key={order.id} className="flex items-center p-6 rounded-lg shadow-lg m-4">
                        <div className="flex flex-col items-start gap-4">
                            <div className="flex flex-col items-start gap-1">
                                <h3 className=" font-bold">
                                    {order.ship_to.name}
                                </h3>
                                <div className="flex items-center gap-2 text-muted-foreground">
                                    <span>Id: {order.order_id.substring(0, 12)}</span>
                                    <div className="h-3 w-3 rounded-full bg-muted" />
                                    <span>Vikt: {totalWeight.toFixed(2)}kg</span>
                                </div>
                            </div>
                            <div className="flex items-center gap-4">
                                {order.order_status === "open" ? <Badge variant={'destructive'}>Ska packas</Badge> : <Badge className="bg-[#ffA500] text-black">Påbörjad</Badge>}
                                <div className="text-base">Artiklar: {`${order.order_lines.length - 1}`}</div>
                            </div>
                        </div>
                    </Card>
                    {order.order_note && order.order_note.length > 1 ? (
                        <Card key={order.id} className="flex p-6 rounded-lg shadow-lg m-4">
                            <h2 className="w-full">
                                {order.order_note}
                            </h2>
                        </Card>
                    ) : (
                        <Card key={order.id} className="flex p-6 rounded-lg shadow-lg m-4">
                            <h2 className="w-full">
                                inga anteckningar
                            </h2>
                        </Card>
                    )}
                </DialogDescription>
                <Separator />
                <DialogHeader>
                    <DialogTitle className="m-2">Produkter</DialogTitle>
                    <Progress className="sticky top-4 shadow-2xl" value={calculateProgress()} />
                    {order.order_lines.map((line: any, index: number) => (
                        <Card key={index} className="flex items-center p-6 rounded-lg shadow-lg m-4">
                            <div className="flex flex-col items-start gap-4 w-full">
                                <div className="flex flex-col items-start gap-1">
                                    <h3 className=" font-bold">
                                        {line.item_name}
                                    </h3>
                                    <div className="flex items-center gap-2 text-muted-foreground">
                                        <span>Id: {line.id}</span>
                                        <div className="h-3 w-3 rounded-full bg-muted" />
                                        <span>Vikt: {line.unit_weight}gr</span>
                                    </div>
                                </div>
                                <div className="flex items-center gap-4 font-bold ">
                                    <div>{Math.floor(line.quantity)} st</div>
                                </div>
                            </div>
                            <div className="ml-auto">
                                <Checkbox
                                    checked={checkedItems.includes(index)}
                                    onClick={() => handleCheckboxChange(index, line.id, order.id, line.quantity)}
                                />
                            </div>
                        </Card>
                    ))}
                    {order.fulfillment_status === "fulfilled" || "partially_fulfilled" ?
                        <Button className="bg-[#00FF00] text-black"
                        onClick={()=> ida()}>
                            Printa label
                        </Button> : ''
                    }
                </DialogHeader>
            </DialogContent>
        </Dialog>
    )
}

The backend where i call all function print, find and etcetera for the api

"use server"

import { Orders } from "@/lib/types/shipmondo"
import { Product } from "@/lib/types/wix";
import { revalidatePath } from 'next/cache'



export const putStatus = async (order_id: string) => {
  const url = "https://app.shipmondo.com/api/public/v3/sales_orders/" + order_id;
  const options = {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      Authorization: 'Basic *********=='
    },
    body: '{"order_status":"on_hold"}'
  };

  const resp = await fetch(url, options);
  const data = await resp.json();
  console.log(data.order_status, data.id);
  revalidatePath('/packning/packas')
  revalidatePath('/packning')
  return data
}

// export const cancel = async (order_id: string) => {
//   const url = "https://app.shipmondo.com/api/public/v3/sales_orders/" + order_id;
//   const options = {
//     method: 'PUT',
//     headers: {
//       'Content-Type': 'application/json',
//       Accept: 'application/json',
//       Authorization: 'Basic *********=='
//     },
//     body: '{"order_status":"open"}'
//   };

//   const resp = await fetch(url, options);
//   const data = await resp.json();
//   revalidatePath('/packning/packas')
//   revalidatePath('/packning')
//   return data
// }
const checkFurfilled = async (order_id: string) => {
  const url = `https://app.shipmondo.com/api/public/v3/sales_orders/` + order_id;
  const options = {
    method: 'GET',
    headers: {
      Accept: 'application/json',
      Authorization: 'Basic *******=='
    }
  }

  const response = await fetch(url, options);
  const data = await response.json();
  await findId(order_id); // <--- added await here
  return data;
}

export const createSale = async (order_id: string) => {
  const url = `https://app.shipmondo.com/api/public/v3/sales_orders/${order_id}/create_shipment`;
  const options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      Authorization: 'Basic *********=='
    },
  }

  const fulfillmentStatus = await checkFurfilled(order_id);
  console.log(fulfillmentStatus.fulfillment_status)
  if (fulfillmentStatus.fulfillment_status === "fulfilled") {
    const resp = await fetch(url, options);
    const data = await resp.json();
    console.log("allt gick genom")
    return data;
  } else {
    console.error("Error: Något gick fel. Order ID:", order_id, "Fulfillment Status:", fulfillmentStatus.fulfillment_status)
  }
}

export const FurfillOrder = async (item_id: string, order_id: string, item_quantity: Number) => {
  const url = `https://app.shipmondo.com/api/public/v3/sales_orders/${order_id}/fulfillments`;
  const options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      Authorization: 'Basic *****=='
    },
    body: `{"fulfillment_lines":[{"order_line_id":${item_id},"shipped_quantity":${item_quantity}}]}`
  };

  try {
    const response = await fetch(url, options);
    const data = await response.json();
    createSale(order_id);
  } catch (error) {
    console.error(error);
  }
};


export const findId = async (order_id: string) => {
  const url = `https://app.shipmondo.com/api/public/v3/sales_orders/` + order_id;
  const options = {
    method: 'GET',
    headers: {
      Accept: 'application/json',
      Authorization: 'Basic *******=='
    }
  }

  const response = await fetch(url, options);
  const data = await response.json();

  let shipmentId = null;
  data?.order_fulfillments?.forEach((fulfillment: any) => {
    if (fulfillment.shipment_id !== null) {
      shipmentId = fulfillment.shipment_id;
    }
  });

  if (shipmentId !== null) {
    console.log('Calling PrintLabel with shipmentId:', shipmentId);
    await PrintLabel(shipmentId); // <--- added await here
  } else {
    console.log('shipmentId is null, not calling PrintLabel');
  }

  return shipmentId;
};


export const PrintLabel = async (shipmentId: number) => {

  const url = 'https://app.shipmondo.com/api/public/v3/print_jobs';
  const options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      Authorization: 'Basic ******=='
    },
    body: `{"document_id":${shipmentId},"document_type":"shipment","host_name":"IT50462","printer_name":"ZDesigner GX420d","label_format":"zpl"}`
  };



  console.log(shipmentId)
  try {
    const response = await fetch(url, options);
    const data = await response.json();
    console.log(data);
    console.log("due gud")
  } catch (error) {
    console.error(error);
    console.log("något gick fel")
  }
}

feel free to ask for further information

New contributor

NikitaFibr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật