0

I am trying to create a build of my nextjs project but it keeps on failing and showing the below error where as it works perfectly during development. I haven't used the 'window.' in my whole project but still getting its error, I tried cleaning the project by deleting its .next and node_modules but it didn't work.

ReferenceError: window is not defined
    at 22462 (path/.next/server/chunks/414.js:5:949)

> Export encountered errors on following paths:
    /dashboard/leads/did-not-hire/page: /dashboard/leads/did-not-hire

/dashboard/leads/did-not-hire/page

"use client";

import { listLeads } from "@/actions/leads";
import {
  Flex,
  Grid,
  LeadCard,
  SpinnerMedium,
  Text2Xl,
} from "@/components/commons";
import { routes } from "@/config";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";

export const dynamic = "force-dynamic";
export const fetchCache = "force-no-store";

const DidNotHire = () => {
  const router = useRouter();
  const [leads, setLeads] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  const getDidNotHireLeads = async () => {
    setIsLoading(true);
    const obj = {
      filter: "is_hired.eq.0",
    };
    const { data, success } = await listLeads(obj);
    setIsLoading(false);

    if (success) {
      setLeads(data);
    }
  };

  useEffect(() => {
    getDidNotHireLeads();
  }, []);

  return (
    <>
      <Flex justify="justify-start">
        <button type="button" onClick={() => router.push(routes.leads.index)}>
          <Flex classes="bg-white w-10 h-10 rounded-full">
            <FontAwesomeIcon icon={faArrowLeft} />
          </Flex>
        </button>
        <Text2Xl text="Did Not Hire" />
      </Flex>

      {isLoading ? (
        <Flex classes="h-[60vh]">
          <SpinnerMedium fill="fill-black" />
        </Flex>
      ) : (
        <Grid classes="my-8">
          {leads.map((lead) => {
            return (
              <div
                key={lead.id}
                className="col-span-12 md:col-span-6 lg:col-span-4 xl:col-span-3"
              >
                <LeadCard
                  bgColor="bg-did-not-hire"
                  lead={lead}
                  setLeads={setLeads}
                  showActions={false}
                />
              </div>
            );
          })}
        </Grid>
      )}
    </>
  );
};

export default DidNotHire;

LeadCard

'use client';

import { changeLeadHiredStatus } from '@/actions/leads';
import {
  BadgeCircle,
  ButtonIcon,
  DropdownOverlay,
  Flex,
  LeadModal,
  ShareAgreementModal,
  TextLg,
  TextMd,
  TextSm,
} from '@/components/commons';
import { constants, hiredDropdownOptions, routes } from '@/config';
import { useToast } from '@/hooks';
import { copyToClipboard, getAmount } from '@/utils';
import {
  faCheck,
  faClone,
  faEnvelope,
  faPhone,
  faSliders,
  faXmark,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useRouter } from 'next/navigation';
import React, { useEffect, useState } from 'react';

const LeadCard = ({
  lead = null,
  setLeads = null,
  bgColor = 'bg-light-gray',
  showActions = true,
  leads = [],
  setFeesQuoted = null,
  formik,
}) => {
  const router = useRouter();
  const { showErrorMessage, showSuccessMessage } = useToast();

  const [isChangingStatus, setIsChangingStatus] = useState(false);
  const [isHiredDropdownOpen, setIsHiredDropdownOpen] = useState(false);
  const [isICAModalOpen, setIsICAModalOpen] = useState(false);
  const [faPhoneClone, setFaPhoneClone] = useState(faClone);
  const [faEnvelopeClone, setFaEnvelopeClone] = useState(faClone);
  const [isEditModalOpen, setIsEditModalOpen] = useState(false);
  const [initValuesForEdit, setInitValuesForEdit] = useState(null);
  const [leadInfo, setLeadInfo] = useState(lead);

  const handleDonotHire = async () => {
    setIsChangingStatus(true);
    const obj = {
      status: 0,
      id: lead.id,
    };
    const { data, success } = await changeLeadHiredStatus(obj);
    setIsChangingStatus(false);
    if (success) {
      // Remove donot hired lead from leads list
      const filteredLeads = leads.filter((lead) => lead.id !== leadInfo?.id);
      setLeads(filteredLeads);
      showSuccessMessage(data);
      setFeesQuoted((prev) => prev - lead.fees_quoted);
    } else {
      showErrorMessage(data);
    }
  };

  const handleClickHiredOption = (val) => {
    if (val === 'send_ica') {
      // setIsICAModalOpen(true);
      router.push(routes.documents.ICA);
    }
    // else if (val == "send_retainer") {
    //   router.push(routes.documents);
    // }
  };

  const handleClickCopy = (copy) => {
    if (copy === 'phone') {
      copyToClipboard(leadInfo?.phone_number);
      setFaPhoneClone(faCheck);

      setTimeout(() => {
        setFaPhoneClone(faClone);
      }, 2000);
    }
    if (copy === 'email') {
      copyToClipboard(leadInfo?.email);
      setFaEnvelopeClone(faCheck);

      setTimeout(() => {
        setFaEnvelopeClone(faClone);
      }, 2000);
    }
  };

  const handleClickUpdate = () => setIsEditModalOpen(true);

  useEffect(() => {
    if (lead?.id) {
      setInitValuesForEdit({
        id: lead?.id,
        first_name: lead?.first_name,
        last_name: lead?.last_name,
        phone_number: lead?.phone_number,
        email_address: lead?.email,
        fees_quoted: lead?.fees_quoted,
        country_of_residence: lead?.country,
        category_id: lead?.category_id,
        applying_for_id: lead?.applying_for_id,
        application_package_id: lead?.application_package_id,
        notes: lead?.notes,
      });
    }
  }, [lead?.id]);

  useEffect(() => {
    setLeadInfo(lead);
  }, [lead]);

  return (
    <>
      <ShareAgreementModal
        isOpen={isICAModalOpen}
        setIsOpen={setIsICAModalOpen}
        email={leadInfo?.email}
      />

      {initValuesForEdit && (
        <LeadModal
          formik={formik}
          key={1}
          isOpen={isEditModalOpen}
          setIsOpen={setIsEditModalOpen}
          initialValues={initValuesForEdit}
          mode={constants.FORM_MODES.edit}
          setLeadInfo={setLeadInfo}
          setFeesQuoted={setFeesQuoted}
        />
      )}

      <div className={`${bgColor} rounded-xl p-4 mb-6`}>
        <div className='flex justify-between'>
          <div>
            <TextLg classes='font-medium' text={`${leadInfo?.first_name} ${leadInfo?.last_name}`} />
            <TextMd
              classes='font-medium'
              text={getAmount(leadInfo?.fees_quoted)}
              color='text-text-gray'
            />
          </div>
          {initValuesForEdit && (
            <FontAwesomeIcon
              icon={faSliders}
              className='bg-slightly-gray p-2 rounded-lg cursor-pointer'
              color='white'
              onClick={handleClickUpdate}
            />
          )}
        </div>

        <div className='mt-4 flex items-center gap-3'>
          <FontAwesomeIcon icon={faPhone} className='text-slightly-gray' />
          <TextSm text={leadInfo?.phone_number} />
          <FontAwesomeIcon
            icon={faPhoneClone}
            onClick={() => handleClickCopy('phone')}
            className='text-slightly-gray p-2 rounded-lg cursor-pointer'
          />
        </div>
        <div className="relative flex items-center gap-3 group">
          <FontAwesomeIcon icon={faEnvelope} className="text-slightly-gray" />
          <div className="relative">
            <TextSm
              text={leadInfo?.email}
              classes="truncate w-42 lg:w-40 overflow-ellipsis whitespace-nowrap"
            />
            <div className="absolute left-1/2 transform -translate-x-1/2 mt-2 hidden group-hover:flex items-center">
              <div className="relative z-10 p-2 text-xs leading-none text-white whitespace-no-wrap bg-black shadow-lg rounded">
                {leadInfo?.email}
                <svg
                  className="absolute left-0 w-full h-2 text-black top-full"
                  x="0px"
                  y="0px"
                  viewBox="0 0 255 255"
                  xmlSpace="preserve"
                >
                  <polygon
                    className="fill-current"
                    points="0,0 127.5,127.5 255,0"
                  />
                </svg>
              </div>
            </div>
          </div>
          <FontAwesomeIcon
            icon={faEnvelopeClone}
            onClick={() => handleClickCopy('email')}
            className='text-slightly-gray p-2 rounded-lg cursor-pointer'
          />
        </div>

        <Flex classes="my-4" gap="gap-2" alignItems="items-center">
          <BadgeCircle
            text="Digital Marketing"
            color="bg-badge-gray"
            width="w-full"
            fontSize="text-xs"
            height="h-8"
            classes="px-2"
          />
          <BadgeCircle
            text="Referral"
            color="bg-badge-gray"
            width="w-full"
            fontSize="text-xs"
            height="h-8"
            classes="px-2"
          />
          <BadgeCircle
            text="Website"
            color="bg-badge-gray"
            width="w-full"
            fontSize="text-xs"
            height="h-8"
            classes="px-2"
          />
        </Flex>
        {showActions && (
          <div className='flex gap-2 relative'>
            <ButtonIcon
              icon={faCheck}
              color='bg-btn-success'
              isDisabled={isChangingStatus}
              onClick={() => setIsHiredDropdownOpen(true)}
              text='Hired'
              width='w-24'
              height='h-9'
              borderRadius='rounded-xl'
            />

            <DropdownOverlay
              email={leadInfo?.email}
              options={hiredDropdownOptions}
              isOpen={isHiredDropdownOpen}
              setIsOpen={setIsHiredDropdownOpen}
              left='-left-2'
              onClick={handleClickHiredOption}
            />

            <ButtonIcon
              icon={faXmark}
              color='bg-btn-danger'
              text='Do Not Hire'
              onClick={handleDonotHire}
              isLoading={isChangingStatus}
              width='w-40'
              height='h-9'
              borderRadius='rounded-xl'
            />
          </div>
        )}
      </div>
    </>
  );
};

export default LeadCard;

I haven't used window. anywhere in the project

5
  • This is a common issue in NextJs when you are serving from the server side, the server does not have access to the browser's window Commented Jul 5 at 16:49
  • Can i see the content of the LeadCard? Commented Jul 5 at 16:52
  • @AkinniyiAkinbodeBolade i just added it in question Commented Jul 5 at 16:56
  • There are so many things happening in your project, can you trace it to the component where you are calling window. Commented Jul 5 at 17:02
  • I just added s shot, i haven't used window. anywhere in the whole project but still it throws error Commented Jul 5 at 17:04

1 Answer 1

1

This error happens if any imported package tries to access the window (or document) variable without checking if it was defined beforehand. The problem is that Next.js continues to build components on the server (where the window isn't defined) even when "use client"; is called.

The easiest solution to this is to add if (typeof window === 'undefined') return null; at the top of your root client component in which the responsible package is used.

That said, a cleaner solution is to find the responsible component and import it using Next.js dynamic imports with ssr: false:

import dynamic from 'next/dynamic';

const ClientOnlyComponent = dynamic(() => import('../components/YourComponent'), {
  ssr: false,
});

export default function Page() {
  return <ClientOnlyComponent />;
}
2
  • I tried commenting all packages in /dashboard/leads/did-not-hire/page but still error Commented Jul 5 at 17:11
  • I don't have experience with the page router, but if it works the same way the app router does, the faulty package might be imported in a higher file, like /dashboard/leads/page, /dashboard/page, or the application's root.
    – Kinan Dira
    Commented Jul 5 at 17:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.