AssertionError [ERR_ASSERTION]: 0 == 2 [closed]

    function getCountOfOddNumbers(number) {
      let sum = 0;
      let i = 1;
      while (i <= number) {
        if (i % 2 !== 0) {
          sum += 1;
        }
        i += 1;
      }
      return sum;
    }

I keep receiving the below error, however, the function does work and counts the odd numbers

getCountOfOddNumbers returns count of not even numbers from zero to the resulting number:
AssertionError 0 == 2

I tried to use for loop instead

HTMX inline validation & browser autofill

I have an input like this:

<input class="form-control"
       id="phone"
       type="tel"
       hx-post="/validate"
       hx-select="#phone-number-validation"
       hx-target="#phone-number-validation"/>

Which works well for the most part, but doesn’t play nice with the browser’s auto fill.

The scenario is that if I submit the form without filling in any inputs (thus failing validation) then subsequently use the browser autofill on say an email input above this input (which populates the phone input at the same time), I would expect HTMX to make the inline validation request and clear the validation message from the previous submit, but no request is made; presumably because the input’s change event is fired from autofill.

How can I ensure that the inline validation requests are fired when inputs are populated via the browsers autofill?

Testing TypeScript code compiled with the module: none option

I have TypeScript code, being compiled with the "module": "none" option and single output JavaScript file. I need a JavaScript code that I can run directly in the browser console.

I want to write tests for my TypeScript code. I tried using Jest, but it seems to require import syntax, which isn’t an option for me because import isn’t compatible with the browser cosnole so I wouldn’t be able to run my compiled JavaScript in the console.

What tool and approach can I take to test my TypeScript code while keeping the "module": "none" option, single output file and JavaScript code that can run in the browser console?

How to handle clickable command links in Telegram bot messages using Telegraf (Node.js)?

I’m building a Telegram bot using Node.js and Telegraf. I want to send messages with clickable HTML links that navigate users to different scenes when clicked.

Currently, I’m sending messages like this:

const message = `
Your assets
ABC Sell or buy
Amount: 173455050828209 SOL
Buy price: 1.0374
Current price: 1.0925
P/L: 0.0002 SOL`;

I want the “Sell or buy” text to be a clickable link that takes the user to a trade scene. What’s the best way to implement this without using inline keyboards?

The most reliable way to implement clickable command links in Telegram bot messages is to use the bot’s start command, here what i tried. but sometimes when i navigate to frequently links are becoming unresponsive.

const message = `
Your assets
ABC <a href="https://t.me/your_bot?start=trade_${encodeURIComponent(asset.name)}">Sell or buy</a>
Amount: ${asset.amount} SOL
Buy price: ${asset.buyPrice}
Current price: ${asset.currentPrice}
P/L: ${asset.pl} SOL
`;

ctx.reply(message, { parse_mode: 'HTML' });


bot.command('start', async (ctx) => {
  const param = ctx.message.text.split(' ')[1]; // gets trade_assetName'
  if (param && param.startsWith('trade_')) {
    const assetName = param.split('_')[1];
    await ctx.scene.enter('tradeScene', { asset: assetName });
  }
});

Value for argument “documentPath” is not a valid string

I am getting an error in one my firebase functions. I have several other functions that are built exactly the same way so I can’t figure out why this one function is failing.

This is my function def:

const PROGRAM_COLLECTION_NAME = 'trainingPrograms';
const PROGRAM_SESSION_COLLECTION_NAME = 'programSession';
const PROGRAM_SESSION_PREVIEW_COLLECTION_NAME = 'programSessionPreview';

export const updatePreviewOnProgramSessionUpdate =
  v2.firestore.onDocumentUpdated(
    `${PROGRAM_COLLECTION_NAME}/{docId}/${PROGRAM_SESSION_COLLECTION_NAME}/{docId}`,
    (event) => {
      const newValue = event.data.after.data();
      if (!newValue) {
        log('No data associated with the event');
        return;
      }

      const preview = {
        docId: newValue['docId'],
        programId: newValue['programId'],
        programWeek: newValue['programWeek'],
        programDay: newValue['programDay'],
        title: newValue['title'],
        subTitle: newValue['subTitle'],
        description: newValue['description'],
        updatedDate: new Date(),
        updatedByUserId: newValue['updatedByUserId'],
      };

      const docPath = `${PROGRAM_COLLECTION_NAME}/${newValue.get(
        'programId'
      )}/${PROGRAM_SESSION_PREVIEW_COLLECTION_NAME}`;

      return db
        .collection(docPath)
        .doc(newValue['docId'])
        .set(preview, { merge: true });
    }
  );

I get the following error in my logs when this function gets triggered:

functions: Error: Value for argument “documentPath” is not a valid
resource path. Path must be a non-empty string.

I have read a lot of the other questions with this error but they did not help as I have other functions built exactly the same way that do work, the only difference being the document paths. But I cannot figure out what I am getting wrong with the paths in this function.

Also, any time I try to use the built in logger:
import { log } from 'firebase-functions/logger';
it does not write any logs to the emulator web UI.

I also tried adding –inspect-functions to the start command for the emulators and still no logs.

Can someone help me figure out why I am getting this error?

EDIT 1

when the first document gets updated the function updates the target “preview” doc.

the actual path of the file triggering the function is:

trainingPrograms/{docId}/programSession/{docId}

the target file to be updated is:

trainingPrograms/{docIdId}/programSessionReview/{docId}

the first {docId} is the document id for the doc in the trainingPrograms collection

EDIT 2

logging issue:

here is a simple function:

export const updatePreviewOnTrainingProgramUpdate = v2.firestore.onDocumentUpdated(
    `${PROGRAM_COLLECTION_NAME}/{docId}`,
    (event) => {
      log('log');
  );

I can see that this function gets called because my functions logs show the following:

function[us-central1-updatePreviewOnTrainingProgramUpdate] Beginning execution of "us-central1-updatePreviewOnTrainingProgramUpdate"

function[us-central1-updatePreviewOnTrainingProgramUpdate] Finished "us-central1-updatePreviewOnTrainingProgramUpdate" in 72.4822ms

but the log message is not present

Dynamic adjusting tooltip content position on hovering tooltip–Angular 17

I want to show some content on hovering tooltip icon.

Eg: label with this icon(!).
Total Fund value (!). I want to show some content in a box of fixed width of 286px, On hovering icon.

The label can be small or longer then the above example.
The content should auto adjust it position according to the surrounding space.

I tried different approach

  1. Given the content fixed top and left value for one label but this approach doesn’t work for every cases and if the label is present at the any corner of the screen then it is overflowing.
  2. I have taken the icon offsetTop and offsetBottom property value also. But this doest work as well.

This is my html structure.

<div class="tooltip-container">
   <div class="flex flex-row align-center">
      <label>{{label}}</label>
      <img src="tooltio.svg"             (click)="onClick($event)"/>
  </div>
  
  <div class="content">
    <p>{{content}}</p>
  </div>
</div>

Individual Practice Enhancement [closed]

Please help:

this is my project:

Changes to document (likely an invoice or statement) for Dr. Jermyn’s practice. Here’s a breakdown of the specific requests: (This changes need to be made if it’s this specific practice, else if not… keep code as is currently)

  1. Remove Name and PR Number under the Invoice Number:

    • Dr. Jermyn wants his name and professional registration (PR) number to be removed from under the invoice number.
  2. Replace Invoice Number with Date:

    • Dr. Jermyn prefers the date to be more visible, ideally replacing the invoice number with the date, as this is something patients would typically look for first. The invoice number should be removed or replaced with the date instead.
  3. Change “Debtor Details” to “Patient Details”:

    • The section labeled “Debtor Details” should be changed to “Patient Details.”
  4. Add Patient Email Field:

    • A field for the patient’s email address needs to be added to the document.
  5. Remove Visit Details:

    • The section for visit details should be removed, as Dr. Jermyn believes it is unnecessary for a cash-based practice.
  6. Simplify the Date and DOS (Date of Service):

    • Dr. Jermyn feels the document has too much repetition. Specifically:

      • The date should be made more prominent.

      • The Date of Service (DOS) is being repeated and is causing confusion. It should appear only once, not as part of the tariff code.

  7. Remove Statement Header:

    • Dr. Jermyn wants the statement header deleted, leaving only the letterhead.
  8. Fix Watermark Issue:

    • The watermark on the document has disappeared, and Dr. Jermyn wants it restored or fixed.
  9. Overall Simplification:

    • Dr. Jermyn desires a more simplified invoice with less repetition of information.

THIS IS ONE EXAMPLE YOU CAN FOLLOW FROM A EXAMPEL CONFIG PROJECT I DID:

var message;

if ( window.main && window.main.hassenChanges ) {

message = ‘Dear ‘ + patientName + ‘nnThis is a reminder of your appointment booked with DR M HASSEN at ‘ + appointmentTime + ‘ in Lenmed Hospital, Block C, Room 114.nnKindly confirm with your medical aid if specialist authorization is needed.nnRegardsnDr M Hassen’;

} else {

message = ‘Dear ‘ + patientName + ‘ nnThis is a reminder of your appointment booked with ‘ + practiceName + ‘ at ‘ + appointmentTime + ‘ on ‘ + appointmentDate + ‘ nnRegards n’ + practiceName;

}

THE CONFIG IN THE CONFIG FILE WAS:

// Configuration for Dr. M Hassen (PR0782955)

this.HASSEN_CHANGES = [‘0782955’];

For this project, i did my config:

// Rohan – Chiropractic Change – Dr Jermyn PR0150894

this.CHIROPRACTITIONER_CHANGES = [‘0150894’];

there is the file where I need to do my solution:

            <div class="width-100-p float-left borders-rounded border-black padding-sides-5-px">

           

                            <div class="width-30-p float-left">

           

                                            <div id="report-phonelist" class="width-100-p float-left">

                                                           

                                            </div>

                                           

                                            <div id="report-emaillist" class="width-100-p float-left">

                                                           

                                            </div>

                           

                            </div>

                           

                            <!-- spacer -->

                            <div class="width-5-p float-left"> &nbsp; </div>



                            <div>



                                            <div id="report-addresslist" class="width-30-p float-left ">

                                                           

                                            </div>

                                           

                            </div>



                            <div>



                                            <div id="report-poslist" class="width-30-p float-left padding-top-10-px %tmp_show_location% ">

                                                            <span class="imitate-h2 color-orange">%stringz_pos_location%</span><br/>

                                                            <div><span>%tmp_report_pos%</span> </div>

                                            </div>



                                                            <!-- spacer -->

                                            <div class="width-5-p float-left"> &nbsp; </div>

                            </div>  

                                           

                            <div id="report-practicedetails" class="width-30-p float-left">

                           

                                            <ul class="text-align-left">

                                           

                                                            <li class="margin-bottom-15-px word-break-all width-100-p float-left">

                                                                            <span class="imitate-h2 color-orange">%stringz_employer_practicenumber%</span><br/>

                                                                            <span>%employer_practice_number%</span>

                                                            </li>

                                           

                                                           

                                                            <li class="margin-bottom-15-px word-break-all width-100-p float-left">

                                                                            <span class="imitate-h2 color-orange">%stringz_employer_practicehpcsanumber%</span><br/>

                                                                            <span>%employer_practice_hpcsa_number%</span>

                                                            </li>

                                                           

                                                           

                                                            <li class="margin-bottom-5-px word-break-all width-100-p float-left" id="report-vat-details">

                                                                            <span class="imitate-h2 color-orange">%stringz_employer_practicevatnumber%</span><br/>

                                                                            <span>%employer_practice_vat_number%</span>

                                                            </li>

                                                           

                                            </ul>

                           

                            </div>

                           

            </div>

 

            <div class="width-100-p float-left borders-rounded border-black padding-sides-5-px">

           

                            <div id="report-patient" class="width-15-p float-left">

                           

                                            <ul class="text-align-left">

                                           

                                                            <li class="margin-bottom-5-px word-break-all width-100-p float-left">

                                                                            <span class="imitate-h2 color-orange">%stringz_report_patientdetails%</span><br/>

                                                                            <span>%stringz_bill_accountref%</span> : <span>%tmp_account_uuid%</span><br/>

                                                                            <span>%tmp_bill_full_name%</span><br/>

                                                                            <span>%tmp_bill_id_or_dob%</span>

                                                            </li>

                                                           

                                            </ul>

                                           

                                            <div id="report-patientcontactcell" class="width-100-p float-left">

                                                            &nbsp;

                                            </div>

                                           

                            </div>



                            <!--spacer-->

                            <div class="width-3-p float-left"> &nbsp; </div>



                            <div>



                                            <div id="report-patientaddresslist" class="width-14-p float-left ">

                                                            &nbsp;

                                            </div>

                                           

                            </div>

                           

                            <!--

                            <div class="width-5-p float-left"> &nbsp; </div>

                           

                            <div id="report-patientcontact" class="width-15-p float-left">

                                            ...

                            </div> spacer -->

                           

                            <!-- spacer -->

                            <div class="width-3-p float-left"> &nbsp; </div>

                           

                            <div id="report-scheme" class="height-120-px width-20-p float-left %tmp_show_medical_scheme%">

                           

                                            <ul class="text-align-left">

                                           

                                                            <li class="margin-bottom-15-px word-break-all width-100-p float-left ">

                                                                            <span class="imitate-h2 color-orange">%stringz_report_medicalschemedetails%</span><br/>

                                                                            <span>%medical_scheme_admin%</span> <span>%medical_scheme_plan%</span><br/>

                                                                            <span>%stringz_report_membership%</span> : <span>%medical_scheme_dependent_membership_code%</span><br/>

                                                                            <span>%stringz_report_dependent%</span> : <span>%medical_scheme_dependent_code%</span><br/>

                                                            </li>

                                                           

                                            </ul>

                                           

                            </div>



                            <!--spacer-->

                            <div class="width-3-p float-left"> &nbsp; </div>



                            <div id="report-att-doc" class="height-120-px display-none width-9-p float-left">

                           

                                            <ul class="text-align-left">

                                           

                                                            <li class="margin-bottom-15-px word-break-all width-100-p float-left ">

                                                                            <span class="imitate-h2 color-orange">%stringz_bill_attdoc%</span><br/>

                                                                            <span>%att_doc%</span>

                                                            </li>

                                                           

                                            </ul>

                                           

                            </div>

                           

                            <!-- spacer -->

                            <div class="width-3-p float-left"> &nbsp; </div>

                           

                            <div id="report-billmeta" class="width-18-p float-left">



                                            <ul class="text-align-left">



                                                            <li class="margin-bottom-15-px word-break-all width-100-p float-left %tmp_show_visit_meta%">

                                                                            <span class="imitate-h2 color-orange">%stringz_bill_visitdetails%</span><br/>

                                                                            <span class="%tmp_show_claim_ref%">%stringz_report_claimref% : </span><span class="%tmp_show_claim_ref%">%tmp_claim_number%</span><br/>

                                                                            <span class="%tmp_show_invoice_num%">%stringz_claims_invoicenumber% : </span><span class="%tmp_show_invoice_num%">%tmp_bill_invoice_uuid%</span><br/>

                                                                            <!-- <span>%stringz_report_dos%</span> : <span>%tmp_report_dos%</span><br/> -->

                                                                            <!-- <span>%stringz_report_received%</span> : <span>%tmp_report_received%</span><br/> -->

                                                                            <span>%stringz_report_preauth%</span> : <span>%tmp_report_preauth%</span><br/>

                                                            <span>%stringz_report_labref%</span> : <span>%tmp_report_labref%</span><br/>

                                                                            <span>%stringz_report_refdoc%</span> : <span>%tmp_report_refdoc%</span><br/>

                                                                            <div class="%tmp_report_isacute_display%">

                                                                            <span>%stringz_report_medicationtype%</span> : <span>%tmp_report_isacute%</span><br/>

                                                                            </div>

                                                                            <span>%stringz_bill_placeofservice%</span> : <span>%tmp_report_inrooms%</span>

                                                                           

                                                            </li>

                                           

                                            </ul>

                                                           

                            </div>

           

            </div>

           

 

            <div class="width-100-p float-left borders-rounded border-black padding-5-px">





                            <!-- spacer -->

                            <div class="float-left"> &nbsp; </div>

                           

                            <span class="imitate-h2 color-orange">%stringz_company_description%</span><br/><br/>



                            <div id="report-companydetails" class="margin-bottom-5-px word-break-all width-100-p float-left">

                                           

                            </div>



                            <!-- maybe here {Joh Deh} -->



            </div>

you need to do the changes here only if its that specific practice.

I tried using the config in the file but it didn’t work. I placed the config in a config settings of its own, in a config file

Implement the body of the customSort(table, criteria) function

The first argument of customSort() is an array of JavaScript objects. The function should sort the array on the property given as the second argument criteria in descending order. The property is numerical only.

Will be sorted by customSort(a, 'id') as:

var a = [{ key:6}, {key:9},{key:2},{key:1},{key:12},{key:63},{key:20}, {key:25},{key:13},{key:19},{key:32},{key:70},{key:14},{key:7},{key:8}]

print(display(a, 'key'));

customSort(a, 'key');

print(display(a, 'key')); //Expected: 70,63,32,25,20,19,14,13,12,9,8,7,6,2,1

Reattach event listener after removing it, in Angular

I have a modal with two buttons: one in the header and one in the modal body. Currently, when the modal opens, the focus automatically goes to the button in the modal body, but I want it to focus on the header button.

To address this, I wrote a function that adds an event listener to the modal button, and within that function, I included the code to focus on the header button.

My code is as follow:


triggerBtn(){
    const modalBtnDiv = document.querySelector('.modal-div');
    const headerBtn = document.querySelector('.header-btn');
    const myFocusEvent =(e) =>{
      headerBtn.focus(); 
      modalBtnDiv.removeEventListener('focus', myFocusEvent);
    };
    modalBtnDiv.addEventListener('focus', myFocusEvent);
}

However, the issue is that focusEvent() is triggered only once. When triggerBtn() is called again, focusEvent() doesn’t work because, after the listener is removed, it isn’t being reattached. And if I don’t remove the event listener, the focus stays on header btn and does not go to the next button.

Is there a way to resolve this and ensure the focus works as intended?

Form validation: can’t enable submit button after validating fields

I’m working on a form (html, css, javascript and jquery for validating zip code) for a friend (I’m not a programmer at all) and I think I got all validations right.

Thing is, the form has submit button disabled and should be enabled if all validations pass, which doesn’t happen.

Nothing in the console, no clue what I’m missing.

Here’s the Fiddle:
text

This is the function to validate the other functions:

function validateForm() {
    const nameValid = validateName1();
    const cpfValid = validateCPF();
    const phoneValid = validatePhone();
    const cepValid = validateCEP();

    submitButton.disabled = !(nameValid && cpfValid && phoneValid && cepValid);
}

If anyone could give some light, I’ll be very happy and glad.

Thank you in advance.

Console, log, debug, browsers, Gemini

Clerk authentication redirecting to /sign-in/sso-callback after signing in with google in next15

I have a fresh next15 application and have used Clerk for an authentication and enabled google sign in, in the clerk dashboard.

import { SignedIn, SignedOut, UserButton } from "@clerk/nextjs";
import Link from "next/link";
import {FaSearch} from "react-icons/fa"

export default function Header() {
  return (
    <header className="bg-slate-200 shadow-md">
      <div className="flex justify-between items-center max-w-6xl mx-auto p-3">
        <Link href="/">
          <h1 className="font-bold text-sm sm:text-xl flex flex-wrap">
            <span className="text-slate-500">Real</span>
            <span className="text-slate-700">Estate</span>
          </h1>
        </Link>
        <form className="bg-slate-100 p-3 rounded-lg flex items-center">
          <input 
            type="text"
            placeholder="Search..."
            className="bg-transparent focus:outline-none w-24 sm:w-64"
          />
          <button>
            <FaSearch className="text-slate-600" />
          </button>
        </form>
        <ul className='flex gap-4'>
          <Link href='/'>
            <li className='hidden md:inline text-slate-700 hover:underline'>
              Home
            </li>
          </Link>
          <Link href='/about'>
            <li className='hidden md:inline text-slate-700 hover:underline'>
              About
            </li>
          </Link>
          <SignedIn>
            <UserButton />
          </SignedIn>
          <SignedOut>
            <Link href='/sign-in'>
              <li className='hidden md:inline text-slate-700 hover:underline'>
                Sign In
              </li>
            </Link>
          </SignedOut>
        </ul>
      </div>
    </header>
  )
}

When I log in with google, it redirects to /sign-in/sso-callback and says “The External Account was not found.” After 3 or 4 times clicking sign in with google, then it creates user and redirect to “/” user automatically.

Vuelidate is always fail on validation

So I have an a component with composable, one of them is modal, so the modal is only the canvas, I just pass the slot to the body, but when I do a create data, the vuelidate is always failing even though the data is filled.
I’ve tried to $v.$reset();it and it still error on validate

TestHoliday.vue

<template>
  <div>
    <div class="card w-full rounded-none border border-gray-300">
      <div
        class="card-body bg-gray-200 p-3 flex flex-col md:flex-row justify-between"
      >
        <div class="mb-3 md:mb-0">
          <h3 class="text-xl font-bold text-primary flex justify-start">
            Holiday Table
          </h3>
        </div>
        <div class="flex flex-col md:flex-row">
          <button
            @click="openModal"
            class="btn btn-primary btn-sm text-white mb-2 md:mb-0 md:mr-2"
          >
            Add Holiday
          </button>
          <button
            class="btn btn-secondary btn-sm text-white mb-2 md:mb-0 md:mr-2 w-full md:w-36"
            @click.prevent="generateHoliday"
            :disabled="stateLoading == true"
          >
            <div
              :class="
                stateLoading
                  ? 'loading loading-spinner loading-sm text-white'
                  : ''
              "
            >
              Generate Holiday
            </div>
          </button>
        </div>
      </div>
    </div>
    <div class="card w-full bg-white rounded-none mb-5">
      <div class="card-body text-gray-700 p-3">
        <div class="overflow-x-auto">
          <TableManageHolidays></TableManageHolidays>
        </div>
      </div>
    </div>

    <!-- Modal -->
    <Modal
      :isOpen="showModal"
      :isAlertExists="stateAlert"
      :alertMessage="alertMessage"
      @close="closeModal"
      @click.self="closeModal"
      @update:isAlertExists="updateAlertState"
    >
      <!-- Slot for header -->
      <template #header>{{ isEditing ? "Edit" : "Add" }} Holiday Date</template>
      <!-- Slot for body -->
      <template #body>
        <form
          id="holidayForm"
          @submit.prevent="submitData"
          class="mt-5 flex flex-col gap-5"
        >
          <div class="flex flex-col gap-2 form-control">
            <label for="name">Holiday Name</label>
            <input
              type="text"
              v-model="state.holiday.name"
              :class="{ invalid: v$.holiday.name.$error }"
              id="name"
              placeholder="Holiday Name"
              class="input input-bordered w-full"
              autofocus
            />
            <span v-if="v$.holiday.name.$error" class="text-sm text-red-500">{{
              v$.holiday.name.$errors[0].$message
            }}</span>
          </div>
          <div class="flex flex-col gap-2 form-control">
            <label for="date">Holiday Date</label>
            <input
              type="date"
              v-model="state.holiday.date"
              :class="{ invalid: v$.holiday.date.$error }"
              id="date"
              placeholder="Holiday Date"
              class="input input-bordered w-full"
            />
            <span v-if="v$.holiday.date.$error" class="text-sm text-red-500">{{
              v$.holiday.date.$errors[0].$message
            }}</span>
          </div>
          <div class="flex flex-col gap-2 form-control">
            <label for="description">Holiday Description</label>
            <textarea
              class="textarea textarea-bordered"
              v-model="state.holiday.description"
              id="description"
              placeholder="Holiday Description (Optional)"
            ></textarea>
          </div>
          <div class="flex justify-end">
            <button
              type="submit"
              :class="isEditing ? 'btn-warning' : 'btn-primary'"
              class="btn btn-primary w-full md:w-auto"
            >
              {{ isEditing ? "Save" : "Add" }} Holiday
            </button>
          </div>
        </form>
      </template>
    </Modal>
  </div>
</template>

<script>
import { useAdminStore } from "@/stores/admin";
import moment from "moment";
import Swal from "sweetalert2";
import { useVuelidate } from "@vuelidate/core";
import { required } from "@vuelidate/validators";
import { computed, onMounted, reactive, ref } from "vue";
import Modal from "@/components/Modal.vue";
import TableManageHolidays from "@/components/admin/department,client/TableManageHolidays.vue";

export default {
  components: {
    Modal,
    TableManageHolidays,
  },
  name: "ManageHolidays",
  setup() {
    const state = reactive({
      holiday: {
        name: "",
        date: "",
        description: "",
      },
    });
    const rules = computed(() => ({
      holiday: {
        name: { required },
        date: { required },
      },
    }));
    const v$ = useVuelidate(rules, state);
    // const v$ = {
    //   $reset: () => {},
    //   $validate: async () => true,
    //   $errors: [],
    // };
    const admin = useAdminStore();

    const showModal = ref(false);

    // ? Alert
    const stateAlert = ref(false);
    const alertMessage = ref("");

    let holidays = ref([]);
    const stateLoading = ref(false);
    const isEditing = ref(false);
    const originalHoliday = ref({});
    const today = ref(new Date());

    const fetchHolidays = async () => {
      const data = await admin.fetchHolidays();
      const mappedHoliday = data.map((item) => {
        return {
          ...item,
          date: moment(item.date).format("DD MMMM YYYY"),
        };
      });
      holidays.value = mappedHoliday;
      return mappedHoliday;
    };

    onMounted(async () => {
      await fetchHolidays();
    });

    return {
      fetchHolidays,
      admin,
      state,
      v$,
      holidays,
      stateLoading,
      isEditing,
      originalHoliday,
      alertMessage,
      today,
      stateAlert,
      showModal,
    };
  },
  methods: {
    formatDate(value) {
      return moment(value).format("DD MMMM YYYY");
    },
    updateAlertState(value) {
      this.stateAlert = value;
    },
    clearForm() {
      this.state.holiday = {
        name: "",
        date: "",
        description: "",
      };
      this.v$.$reset();
    },
    openModal() {
      this.clearForm();
      this.isEditing = false;
      this.showModal = true;
    },
    closeModal() {
      this.showModal = false;
    },
    closeAlert() {
      this.stateAlert = false;
    },
    async submitData() {
      if (this.isEditing) {
        await this.updateData();
      } else {
        await this.addData();
      }
    },
    async addData() {
      console.log("Holiday before validation:", this.state.holiday);
      this.v$.$reset();
      try {
        const isValid = await this.v$.$validate();
        console.log("Validation result:", isValid);
        if (!isValid) {
          console.error("Validation failed:", this.v$.$errors);
          return;
        }

        // Check if the data is exists
        const check = await this.admin.checkHolidayByDate(
          this.state.holiday.date
        );
        // console.log("check console :", check);
        // If the data exists then it will throuw status 200
        if (check.status == 200) {
          // Throw error that data is exists
          // Prevent any creating data with the same date
          throw new Error("Holiday Date already exist!");
        }
      } catch (error) {
        if (error.status == 404) {
          const response = await this.admin.addHoliday(this.state.holiday);

          // this.holidays = await this.admin.fetchHolidays();
          await this.fetchHolidays();
          // this.$refs.theModal.close();
          this.closeModal();
          Swal.fire({
            icon: "success",
            title: "Success...",
            text: response.data.message,
            timer: 2500,
          });
        } else {
          // this.$refs.theModal.showModal();
          this.openModal();
          this.stateAlert = true;
          this.alertMessage = error.message;
          return;
        }
      }
    },
    async editData(holiday) {
      try {
        this.clearForm();
        this.isEditing = true;
        const response = await this.admin.checkHolidayById(holiday.holiday_Id);
        response.date = response.date.split("T")[0];
        this.state.holiday = {
          ...response,
        };
        this.originalHoliday = {
          ...response,
        };
        // this.$refs.theModal.showModal();
        this.openModal();
        console.log("modal: ", showModal);
      } catch (error) {}
    },
    async updateData() {
      try {
        this.v$.$validate();

        if (this.v$.$error) {
          return;
        }

        // Check for changes in data
        if (
          this.state.holiday.name === this.originalHoliday.name &&
          this.state.holiday.date === this.originalHoliday.date &&
          this.state.holiday.description === this.originalHoliday.description
        ) {
          this.stateAlert = true;
          this.alertMessage = "No changes detected!";
          return;
        }
        const response = await this.admin.updateHoliday(this.state.holiday);

        // this.holidays = await this.admin.fetchHolidays();
        await this.fetchHolidays();
        this.closeModal();
        await Swal.fire({
          icon: "success",
          title: "Success...",
          text: response.data.message,
          timer: 2500,
        });
      } catch (error) {
        this.$refs.theModal.showModal();
        Swal.fire({
          icon: "error",
          title: "Error...",
          text: error.data.message,
          timer: 2500,
        });
      }
    },
    async deleteData(id) {
      Swal.fire({
        title: "Apa anda yakin?",
        icon: "warning",
        showCancelButton: true,
        confirmButtonColor: "#3085d6",
        cancelButtonColor: "#d33",
        confirmButtonText: "Yes",
      }).then(async (result) => {
        if (result.isConfirmed) {
          try {
            const response = await this.admin.deleteHoliday(id);
            Swal.fire({
              title: "Success...",
              text: response.data.message,
              icon: "success",
              timer: 2500,
            });
            // this.holidays = await this.admin.fetchHolidays();
            await this.fetchHolidays();
          } catch (error) {
            Swal.fire({
              icon: "error",
              title: "Error...",
              text: error.data.message,
              timer: 2500,
            });
          }
        }
      });
    },
    async generateHoliday() {
      this.stateLoading = true;
      let totalSuccessInsert = 0;
      let totalFailedInsert = 0;
      let totalExistingDate = 0;

      try {
        const googleHoliday = await this.admin.fetchGoogleHoliday();
        const promises = googleHoliday.map(async (data) => {
          try {
            await this.admin.checkHolidayByDate(data.date);
            totalExistingDate += 1;
          } catch (error) {
            if (error.status === 404) {
              const newHoliday = {
                name: data.name,
                date: data.date,
                description: null,
              };

              try {
                await this.admin.addHoliday(newHoliday);
                totalSuccessInsert += 1;
              } catch (error) {
                totalFailedInsert += 1;
              }
            } else {
              totalFailedInsert += 1;
            }
          }
        });
        await Promise.all(promises);

        this.stateLoading = false;
        Swal.fire({
          title: "Holiday Generated!",
          html: `${totalSuccessInsert} Berhasil, ${totalFailedInsert} Gagal, ${totalExistingDate} Telah Ada`,
          icon: "info",
        });

        await this.fetchHolidays();
      } catch (error) {
        this.stateLoading = false;
        Swal.fire({
          title: "Error",
          text: "Failed to fetch holiday data. Please try again.",
          icon: "error",
        });
      }
    },
  },
};
</script>

<style scoped>
span {
  color: red;
  font-size: 0.9em;
}
</style>

Modal.vue

<template>
  <div
    v-if="isOpen"
    class="fixed inset-0 p-8 overflow-auto h-full bg-gray-900 bg-opacity-50 flex items-center justify-center z-50"
  >
    <dialog id="theModal" ref="theModal" class="modal">
      <div class="modal-box">
        <form method="dialog">
          <button
            @click="closeModal"
            class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
          >
            ✕
          </button>
        </form>
        <h3 class="text-lg font-bold">
          <slot name="header">Default Modal Title</slot>
        </h3>
        <div v-if="isAlertExists">
          <!-- Alert Section -->
          <div
            role="alert"
            class="alert alert-warning mb-4 flex items-center justify-between mt-3"
          >
            <div class="flex items-center gap-2">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                class="h-6 w-6 shrink-0 stroke-current"
                fill="none"
                viewBox="0 0 24 24"
              >
                <path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  stroke-width="2"
                  d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
                />
              </svg>
              Warning: {{ alertMessage }}
            </div>
            <!-- Close Alert Button -->
            <button class="btn btn-sm btn-circle btn-ghost" @click="closeAlert">
              ✕
            </button>
          </div>
        </div>
        <div>
          <slot name="body"> </slot>
        </div>
      </div>
      <form method="dialog" class="modal-backdrop">
        <button @click="closeModal">close</button>
      </form>
    </dialog>
  </div>
</template>

<script>
import { nextTick, onMounted, ref } from "vue";
export default {
  props: {
    isOpen: {
      type: Boolean,
      required: true,
    },
    isAlertExists: {
      type: Boolean,
      default: false,
    },
    alertMessage: {
      type: String,
      required: false,
      default: "",
    },
  },
  setup(props) {
    // console.log(props.isAlertExists);
    const showAlert = ref(true);

    return { showAlert };
  },
  watch: {
    isOpen(newVal) {
      nextTick(() => {
        if (newVal) {
          this.$refs.theModal.showModal();
        }
      });
    },
  },

  methods: {
    closeModal() {
      this.$emit("close");
      this.$refs.theModal.close();
    },
    closeAlert() {
      // this.showAlert = false;
      this.$emit("update:isAlertExists", false);
    },
  },
};
</script>

<style scoped>
/* Optional custom styling */
</style>

Just ignore the table component, the problem is on the addData() function that has vuelidate is not working properly

Trying to Email Multiple PDF Blobs in Sheets Javascript

What I want: a Google Sheet that generates pdfs, saves the PDFs to your GDrive, and then sends you a single email with all of the pdfs attached.

What I’ve been able to do:

  • Generate PDFs
  • Save the PDFs to GDrive
  • Email INDIVIDUAL PDFs

The (disgusting hobbyist) code I have loops through the creation of the pdfs just fine, but is gets hung up either when I try to save/push them to an array, or when I try to attach the array to the email.

The (probably) offending lines of code have been called out with a line of

======================================s

  // ======================================== //
  //                                          //
  //      GENERATE MULTIPLE LOGS AT ONCE      //
  //                                          //
  // ======================================== //

function printMultiple() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var ui = SpreadsheetApp.getUi();

  var lastRow = ss.getRange("AN:AN").getValues().filter(String).length;
  var targetRange = ss.getSheetByName("Show 3 Mileage Form").getRange(1,40,lastRow,1);
  var workerList = String(targetRange.getValues()).replaceAll(", ","+++").split(",");

  var printAllBox = ui.alert("PRINT ALL MILEAGE LOGS", "Attempting to generate pdfs for everybody who drove this week.nnThis might take a while, so don't touch anything.",ui.ButtonSet.OK_CANCEL);

    if (printAllBox === ui.Button.OK) {

      var timer = 0;
      var counter = 0;

      for (var i = 0; i < workerList.length; i++) {
        workerList[i] = workerList[i].replaceAll("+++",", ");
        ss.getRange("E2").setValue(workerList[i]);
    
        if (ss.getRange("PRINT!I10").getValue() == ""){  }

        else {
                    
          var sheet;
          var email = Session.getEffectiveUser().getEmail();
          var subject = "Multiple Mileage Logs";
          var body = "Mileage logs generated."

          // Look to see if it's a two pager or not

          if (ss.getRange("PRINT!G1").getValue() == "PAGE 1 of 1") { sheet = ss.getSheetByName("PRINT");}
          else { sheet = ss.getSheetByName("PRINT - 2 PAGE"); }

          // show the print sheet
          sheet.showSheet();

          const fileName = ss.getRange("PRINT!J2").getValue()+".pdf";
                  
          // Base URL
          var exportURL = "https://docs.google.com/spreadsheets/d/SS_ID/export?".replace("SS_ID", ss.getId());

          var url_ext = 'exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
          + '&size=letter'                            // paper size legal / letter / A4
          + '&portrait=false'                         // orientation, false for landscape
          + '&fith=true&'                             // fit to page width, false for actual size  CHANGED TO HEIGHT
          + "&gridlines=false" 
          + "&top_margin=0.25" 
          + "&bottom_margin=0.25" 
          + "&left_margin=0.5" 
          + "&right_margin=0.5" 
          + '&sheetnames=false&printtitle=false'      // hide optional headers and footers
          + '&pagenumbers=false&gridlines=false'      // hide page numbers and gridlines
          + '&fzr=false'                              // do not repeat row headers (frozen rows) on each page
          + '&gid=';                                  // the sheet's Id

          var token = ScriptApp.getOAuthToken();

          //make an empty array to hold your fetched blobs  
          var pdf;
          var pdfCluster = [];

          // Convert your specific sheet to blob
          var response = UrlFetchApp.fetch(exportURL + url_ext + sheet.getSheetId(), {
          headers: { 'Authorization': 'Bearer ' +  token }
          });

          //  And then hide the printsheet
          sheet.hideSheet();

          //convert the response to a blob and store in our array
          pdf = response.getBlob().setName(fileName);

// =======================================================================================

          // I originally tried using the variable "pdf" as the array 
          // and figured that maybe having a completely separate variable might help

          pdfCluster.push(pdf);

// =======================================================================================

          // Check to see if they have the right folders in place, and if not, create them
          var folder1 = "gripPDFs"                          //  gripPDFs
          var folder2 = ss.getRange("PRINT!C5").getValue()  //  Job Name
          var folder3 = "mileage logs"                      //  mileage logs  
          var folder4 = ss.getRange("PRINT!K2").getValue()  //  date

          /* Find the first level folder, create if the folder does not exist */
          var folders = DriveApp.getFoldersByName(folder1);
          var firstLevelFolder = (folders.hasNext()) ? folders.next() : DriveApp.createFolder(folder1);
                                        
          /* Layer2 */
          folders = DriveApp.getFoldersByName(folder2);
          var secondlevelFolder = (folders.hasNext()) ? folders.next() : firstLevelFolder.createFolder(folder2); 

          /* Layer3 */
          folders = DriveApp.getFoldersByName(folder3);
          var thirdlevelFolder = (folders.hasNext()) ? folders.next() : secondlevelFolder.createFolder(folder3); 

          /* Layer4 */
          folders = DriveApp.getFoldersByName(folder4);
          var finalfolder = (folders.hasNext()) ? folders.next() : thirdlevelFolder.createFolder(folder4); 

          // And create that shit
          finalfolder.createFile(pdf);

          counter = (counter + 1);
          timer = timer + 1;
          if (timer > 3) { 
            // Sleep to appease the Google Lag Police
            SpreadsheetApp.flush();
            Utilities.sleep(5000);
            SpreadsheetApp.flush();
            timer = 0;
          }
        }
      }

  //And mail it!
  GmailApp.sendEmail(email, subject, body, {
  htmlBody: body,

// =======================================================================================

  attachments: [pdfCluster]

// =======================================================================================

  });

  var pdfResults = ui.alert("PROCESS COMPLETE",counter +" total logs printed.  The files have been emailed to you and can be found under "+folder1+"/"+folder2+"/"+folder3+"/"+folder4+" in your Google Drive.",ui.ButtonSet.OK);



  }
}


Why does the null coalescing operator not work here? [duplicate]

I am trying to better understand how the nullish coalescing operator (??) in JavaScript is supposed to work. Can someone please explain why this:

let a = b ?? 0;

returns this:

Uncaught ReferenceError: b is not defined

The docs say (emphasis mine):

The nullish coalescing (??) operator is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.

Since b is undefined, my expectation is that a will be assigned the value 0.

rotate image as user scroll using intersection observer

I just saw a wonderful scroll animation in this site https://thehungryfamily.com/bon-bouquet-cafe/.
here as user scroll some icons keep rotating. i tried to mimic the same animation but failed to understand the logic.

what i did so far

  • use intersection observer to detect the icon/image container in the viewport
  • use intersection observer boundingClientRect.y to detect if the user scroll from top-bottom or bottom-top to change rotate behaviour
  • adding values in array for intersection observer threshold so that it keeps trigerring the observer callback

but still somehow i miss some logic. the challenge i am facing is determining the user scroll direction(is user scroll from top to bottom or from bottom to top)

here is my code

function getAngle(str)
{
  if(str)
  {
    let angle=str.split("(");
    let angleArr=angle[1].split("t");
    return parseFloat(angleArr[0]);
  }
}

const globeOptions = {
  rootMargin: '0px',
  threshold: [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1]
}
const globeCallback = entries => {
    entries.forEach(entry => {
        const currentY = entry.boundingClientRect.y
        const currentRatio = entry.intersectionRatio
        const isIntersecting = entry.isIntersecting;
        let prevAngle=
        entry.target.style.transform ? getAngle(entry.target.style.transform):0;
    
        if (currentY < previousY) {
          if (currentRatio > previousRatio && isIntersecting) {
            entry.target.style.transform=`rotate(${prevAngle+0.2}turn)`;
          } else {
            entry.target.style.transform=`rotate(${prevAngle+0.2}turn)`;
          }
        } else if (currentY > previousY && isIntersecting) {
          if (currentRatio < previousRatio) {
            entry.target.style.transform=`rotate(${-(prevAngle-0.2)}turn)`;
          } else {
            entry.target.style.transform=`rotate(${-(prevAngle-0.2)}turn)`;
          }
        }
    
        previousY = currentY
        previousRatio = currentRatio
    })
  }

const globeobserver = new IntersectionObserver(globeCallback, globeOptions)


const globeTarget = document.querySelector('.globe-box img')
globeobserver.observe(globeTarget)