my query on subcollection in firestore does not return any data

I have a subcollection in a document on firestore, I can get all the documents in the subcollection if I do not put any condition in the query. This snipped works

 let q = query(collection(this.firestore,`providers/${providerKey}/locations`))
 onSnapshot(q, snapshot=>callback(snapshot))

if I put any condition:

let q = query(collection(this.firestore,`providers/${providerKey}/locations`))
q = query(q, where("status","!=","DELETED")
onSnapshot(q,snapshot=>callback(snapshot)
     onSnapshot(q, snapshot=>{callback(snapshot)}

I do not get any documents all the document in the subcollection has the field status, that is a string and in it I have documents with status ACTIVE and DELETED, but nothing is found, for sure is my mistake, but I do not understand what is wrong

How can I setup multiple enviroments on my RN App?

I’m trying to set up multiple environment configurations for my React Native app, but I’m having trouble with the iOS setup.

Here’s what I’ve done so far:

I can run the app and switch between environments using the following scripts with react-native-config:

"setDev": "ENVFILE=.env",
"setQA": "ENVFILE=.env.qa",
"ios-dev": "yarn setDev react-native run-ios --mode=Debug --scheme "myAppDev" --simulator='iPhone 13'",
"ios-qa": "yarn setQA react-native run-ios --mode=Debug --scheme "myAppQa" --simulator='iPhone 13'",
"android-dev": "yarn setDev  react-native run-android",
"android-qa": "yarn setQA  react-native run-android",

However, I’m encountering issues with the Firebase configuration.

In my project structure, I have the GoogleService files on:

  • ios folder
    • myApp folder

      • Firebase folder

        • DEV/GoogleService-Info.plist

        • QA/GoogleService-Info.plist

I have created two schemes in Xcode:

  1. myAppQa:

    • In Edit Scheme, I added an environment variable QA with a value of 1.

    • In Pre-Actions, I added this script:

      echo ".env.qa" > /tmp/envfile touch "${PROJECT_DIR}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildDotenvConfig.rb"
      
  2. myAppDev:

    • Similarly, I set the DEV environment variable with a value of 1 and pointed it to .env.dev. And the enviroment DEV with a value of 1

Then, in AppDelegate.mm, I added this code to load the correct GoogleService-Info.plist file based on the build configuration:


// TODO: Add PROD ENV

NSString *filePath;
#if DEV
filePath = [[NSBundle mainBundle] pathForResource:@"Firebase/DEV/GoogleService-Info" ofType:@"plist"];
#elif QA
filePath = [[NSBundle mainBundle] pathForResource:@"Firebase/QA/GoogleService-Info" ofType:@"plist"];
#else 
filePath = [[NSBundle mainBundle] pathForResource:@"Firebase/PROD/GoogleService-Info" ofType:@"plist"];
#endif

FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath];
if ([FIRApp defaultApp] == nil) {
  [FIRApp configureWithOptions:options];
}

When I run yarn ios-qa, the app builds successfully, and with react-native-config, I can access the correct environment variables. However, the Firebase GoogleService-Info.plist that gets loaded is the PROD one (from the else block in AppDelegate). It seems like the environment variables defined in the Scheme aren’t being recognized.

The version of rn is:

"react-native": "0.71.7",

What am I missing here? Im a bit new and im no very familiar with ios and xcode so any advice would be appreciated!

How to reset custom react-select component filed with Formik, React, Typescrypt?

I am implementing a form with the help of the Formik and yup validation in Nextjs or Typescript application. I am using the react-select library for the select box to choose multiple and single values. I have built reusable components of Input, Select, or DatePicker, and Tiptap editor input as shown below. Everything is working fine but there is a problem coming when I am trying to submit the form, form with submitting I am using the Fromik resetForm method to reset all the values from all inputs(Select, Input, DatePicker, Tiptap editor). But is only resetting the Input value not the Select and DatePicker value after submitting the form. I have used the Formik setFieldValue method to reset the Select or DatePicker and Tiptap but not work. Please help me to resolve this issue on how to reset the Select DatePicker and Tiptap input in Formik.

Tiptap.tsx

"use client";

import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import Paragraph from "@tiptap/extension-paragraph";
import Text from "@tiptap/extension-text";
import BulletList from "@tiptap/extension-bullet-list";
import OrderedList from "@tiptap/extension-ordered-list";
import ListItem from "@tiptap/extension-list-item";
import Bold from "@tiptap/extension-bold";
import Italic from "@tiptap/extension-italic";
import Underline from "@tiptap/extension-underline";
import Placeholder from "@tiptap/extension-placeholder";
import { FC } from "react";
import {
  BoldIcon,
  ItalicIcon,
  List,
  ListOrdered,
  UnderlineIcon,
} from "lucide-react";

type TiptapProps = {
  id: string;
  name: string;
  label?: string;
  errorMsg?: string;
  error?: boolean;
  value: string;
  onChange: (value: string) => void;
};

const Tiptap: FC<TiptapProps> = ({
  label,
  error,
  id,
  name,
  value,
  onChange,
  errorMsg,
}) => {
  const editor = useEditor({
    extensions: [
      StarterKit,
      Paragraph,
      Text,
      BulletList,
      OrderedList,
      ListItem,
      Bold,
      Italic,
      Underline,
      Placeholder.configure({
        placeholder: "Write something …",
      }),
    ],
    content: value,
    onUpdate: (value) => {
      const text = value.editor.getHTML().toString();
      onChange(text);
    },
  });

  if (!editor) {
    return null;
  }

  const btnClass = `opacity-70 p-1 rounded`;

  return (
    <div>
      {label && (
        <label
          htmlFor={id}
          className={`text-sm mb-0.5 font-medium ${
            error ? "text-rose-600" : "text-gray-900"
          }`}
        >
          {label}
        </label>
      )}
      <div className="border relative border-gray-300 w-full rounded-md h-[250px] dark:bg-zinc-700 dark:border-zinc-400">
        <div className="flex flex-wrap gap-2 px-4 py-2.5 border-b border-gray-300 dark:border-zinc-400  w-full">
          <button
            type="button"
            onClick={() => editor.chain().focus().toggleBold().run()}
            className={`${btnClass} ${
              editor.isActive("bold")
                ? "bg-neutral-300 dark:bg-neutral-400 opacity-100 text-black"
                : ""
            }`}
          >
            <BoldIcon className="w-5 h-5" />
          </button>
          <button
            type="button"
            onClick={() => editor.chain().focus().toggleItalic().run()}
            className={`${btnClass} ${
              editor.isActive("italic")
                ? "bg-neutral-300 dark:bg-neutral-400 opacity-100 text-black"
                : ""
            }`}
          >
            <ItalicIcon className="w-5 h-5" />
          </button>
          <button
            type="button"
            onClick={() => editor.chain().focus().toggleUnderline().run()}
            className={`${btnClass} ${
              editor.isActive("underline")
                ? "bg-neutral-300 dark:bg-neutral-400 opacity-100 text-black"
                : ""
            }`}
          >
            <UnderlineIcon className="w-5 h-5" />
          </button>
          <div className="sm:block hidden w-[1px] h-6 mx-4 bg-zinc-500 rounded-full"></div>
          <div className="flex items-center gap-2 flex-wrap">
            <button
              type="button"
              className={`${btnClass} ${
                editor.isActive("bulletList")
                  ? "bg-neutral-300 dark:bg-neutral-400 opacity-100 text-black"
                  : ""
              }`}
              onClick={() => editor.chain().focus().toggleBulletList().run()}
            >
              <List className="w-5 h-5" />
            </button>
            <button
              type="button"
              className={`${btnClass} ${
                editor.isActive("orderedList")
                  ? "bg-neutral-300 dark:bg-neutral-400 opacity-100 text-black"
                  : ""
              }`}
              onClick={() => editor.chain().focus().toggleOrderedList().run()}
            >
              <ListOrdered className="w-5 h-5" />
            </button>
          </div>
        </div>
        <EditorContent editor={editor} name={name} id={id} />
        <span className="absolute bottom-4 right-4 text-sm opacity-60">
          {Math.min(value.length, 200)}/200
        </span>
      </div>
      {errorMsg && <small className="text-rose-600 ">{errorMsg}</small>}
    </div>
  );
};

export default Tiptap;

DatePicker.tsx

import dayjs from "dayjs";
import { CalendarDays, ChevronLeft, ChevronRight } from "lucide-react";
import React, { useCallback, useEffect, useRef, useState } from "react";

interface DatePickerProps {
  error?: boolean;
  errorMsg?: string;
  placeholder?: string;
  id: string;
  label?: string;
  value: string;
  name: string;
  onChange: (date: string | null) => void;
}

const DatePicker = (props: DatePickerProps) => {
  const { error, id, label, placeholder, errorMsg, value, onChange, name } =
    props;
  const [currentDate, setCurrentDate] = useState(dayjs());
  const [selectedDate, setSelectedDate] = useState<dayjs.Dayjs | null>(null);
  const [showDatePicker, setShowDatePicker] = useState(false);
  const [showYearPicker, setShowYearPicker] = useState(false);
  const [showMonthPicker, setShowMonthPicker] = useState(false);
  const [selectedYear, setSelectedYear] = useState(currentDate.year());
  const [selectedMonth, setSelectedMonth] = useState(currentDate.month());
  const datePickerRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        datePickerRef.current &&
        !datePickerRef.current.contains(event.target as Node)
      ) {
        setShowDatePicker(false);
        setShowYearPicker(false);
        setShowMonthPicker(false);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, []);

  useEffect(() => {
    if (value) {
      const parsedDate = dayjs(value, "DD MMM, YYYY");
      if (parsedDate.isValid()) {
        setSelectedDate(parsedDate);
        setCurrentDate(parsedDate);
        setSelectedYear(parsedDate.year());
        setSelectedMonth(parsedDate.month());
      }
    }
  }, [value]);

  const daysInMonth = currentDate.daysInMonth();
  const startOfMonth = currentDate.startOf("month").day();
  const days = Array.from(
    { length: daysInMonth + startOfMonth },
    (_, index) => {
      const day = currentDate.startOf("month").add(index - startOfMonth, "day");
      return {
        day,
        isCurrentMonth: day.month() === currentDate.month(),
        isToday: day.isSame(dayjs(), "day"),
        isSelected: day.isSame(selectedDate, "day"),
      };
    }
  );

  const handlePreviousMonth = () =>
    setCurrentDate(currentDate.subtract(1, "month"));

  const handleNextMonth = () => setCurrentDate(currentDate.add(1, "month"));

  const handleDateSelect = (day: dayjs.Dayjs) => {
    setSelectedDate(day);
    setCurrentDate(day);
    onChange(day.format("DD MMM, YYYY"));
    setShowDatePicker(false);
  };

  const toggleDatePicker = useCallback(
    () => setShowDatePicker((prev) => !prev),
    []
  );

  const toggleYearPicker = () => setShowYearPicker(!showYearPicker);

  const handleYearSelect = (year: number) => {
    setSelectedYear(year);
    setCurrentDate(currentDate.year(year).month(selectedMonth));
    setShowYearPicker(false);
    setShowMonthPicker(true);
  };

  const handleMonthSelect = (month: number) => {
    setSelectedMonth(month);
    setCurrentDate(currentDate.year(selectedYear).month(month)); // Update currentDate
    setShowMonthPicker(false);
    setShowYearPicker(false);
  };

  const weeks = ["S", "M", "T", "W", "T", "F", "S"];

  const yearOptions = Array.from(
    { length: dayjs().year() - 1992 + 1 },
    (_, index) => 1992 + index
  );

  const renderButton = (
    key: React.Key,
    onClick: () => void,
    label: string,
    isActive: boolean
  ) => (
    <button
      key={key}
      onClick={onClick}
      className={`mx-1 p-1 rounded transition ${
        isActive
          ? "bg-primary text-white"
          : "dark:hover:bg-zinc-500 hover:bg-gray-200"
      }`}
    >
      {label}
    </button>
  );

  return (
    <div>
      {label && (
        <label
          htmlFor={id}
          className={`text-sm mb-0.5 font-medium ${
            error ? "text-rose-600" : "text-gray-900"
          }`}
        >
          {label}
        </label>
      )}
      <div
        ref={datePickerRef}
        className="relative w-full"
        onClick={toggleDatePicker}
      >
        <input
          id={id}
          type="text"
          placeholder={placeholder}
          name={name}
          value={selectedDate ? selectedDate.format("DD MMM, YYYY") : ""}
          readOnly
          className={`
        w-full
        outline-0
        border
        p-2
        h-11
        rounded-md
        text-sm
        text-gray-900
        focus:ring-1
        ${
          error
            ? "border-rose-600 focus:ring-rose-600 placeholder:text-red-400"
            : "border-gray-300 focus:ring-primary"
        }
      bg-white
      dark:bg-zinc-700
      dark:text-white
      dark:border-zinc-400
      peer

      `}
        />
        <CalendarDays className="absolute top-1/2 -translate-y-1/2 right-2 w-5 h-5 opacity-65 peer-focus:opacity-100 cursor-pointer" />

        {showDatePicker && (
          <div
            onClick={(event) => event.stopPropagation()}
            className="absolute w-full top-12  rounded-md drop-shadow left-0 right-0 bg-white dark:bg-zinc-700 h-fit shadow z-10"
          >
            <div className="h-12 border-b w-full px-4 flex items-center justify-between dark:border-zinc-500 ">
              <button
                type="button"
                onClick={handlePreviousMonth}
                className="w-9 h-9 rounded-full border flex items-center justify-center hover:bg-neutral-300 transition duration-300 dark:hover:bg-zinc-500 dark:border-zinc-400"
              >
                <ChevronLeft size={20} />
              </button>
              <span
                onClick={toggleYearPicker}
                className="font-medium cursor-pointer"
              >
                {dayjs(currentDate).format("MMMM YYYY")}
              </span>
              <button
                type="button"
                onClick={handleNextMonth}
                className="w-9 h-9 rounded-full border flex items-center justify-center hover:bg-neutral-300 transition duration-300 dark:hover:bg-zinc-500 dark:border-zinc-400"
              >
                <ChevronRight />
              </button>
            </div>

            {showYearPicker ? (
              <div className="grid sm:grid-cols-5 grid-cols-3 max-h-[350px] overflow-y-auto gap-4 py-2 px-4">
                {yearOptions
                  .reverse()
                  .map((year) =>
                    renderButton(
                      year,
                      () => handleYearSelect(year),
                      year.toString(),
                      year === selectedYear
                    )
                  )}
              </div>
            ) : showMonthPicker ? (
              <div className="px-4 py-2 grid grid-cols-3 gap-4">
                {Array.from({ length: 12 }, (_, index) =>
                  renderButton(
                    index,
                    () => handleMonthSelect(index),
                    dayjs().month(index).format("MMMM"),
                    index === selectedMonth
                  )
                )}
              </div>
            ) : (
              <>
                <div className="grid grid-cols-7 px-4 py-2 place-items-center">
                  {weeks.map((week, weekIdx) => (
                    <div
                      key={weekIdx.toString()}
                      className="text-sm font-medium text-gray-600 dark:text-neutral-300"
                    >
                      {week}
                    </div>
                  ))}
                </div>
                <div className="grid grid-cols-7  place-items-center gap-2 px-4 py-2">
                  {days.map((day, dayIdx) => {
                    const isToday = day.isToday;
                    const isSelected = day.isSelected;
                    const isCurrentMonth = day.isCurrentMonth;
                    return (
                      <div key={dayIdx.toString()}>
                        <button
                          type="button"
                          onClick={() => handleDateSelect(day.day)}
                          className={`w-8 h-8 flex items-center text-sm rounded-md justify-center ${
                            isToday
                              ? "bg-primary text-white"
                              : isSelected
                              ? "bg-primary text-white"
                              : ""
                          } ${isCurrentMonth ? "" : "opacity-60"}`}
                        >
                          {dayjs(day.day).format("D")}
                        </button>
                      </div>
                    );
                  })}
                </div>
              </>
            )}
          </div>
        )}
      </div>
      {errorMsg && <small className="text-rose-600 px-1">{errorMsg}</small>}
    </div>
  );
};

export default DatePicker;

Select.tsx

import { Option } from "@/types";
import { useTheme } from "next-themes";
import { useMemo } from "react";
import ReactSelect, {
  CSSObjectWithLabel,
  GroupBase,
  MultiValue,
  SingleValue,
  StylesConfig,
} from "react-select";

interface SelectProps {
  id: string;
  placeholder?: string;
  options: string[];
  isMulti?: boolean;
  name: string;
  onChange: (selectedValue: string | string[]) => void;
  value: string | string[];
  error?: boolean;
  label?: string;
  errorMsg?: string;
}

const Select = (props: SelectProps) => {
  const {
    id,
    isMulti,
    placeholder,
    name,
    value,
    onChange,
    options,
    error,
    label,
    errorMsg,
  } = props;
  const { theme } = useTheme();

  const colorStyles: StylesConfig<Option, boolean, GroupBase<Option>> = {
    control: (base: CSSObjectWithLabel) => ({
      ...base,
      borderColor: error
        ? "red"
        : theme === "dark"
        ? "#a1a1aa"
        : base.borderColor,
      boxShadow: error ? "0 0 0 1px red" : base.boxShadow,
      "&:hover": {
        borderColor: error
          ? "red"
          : theme === "dark"
          ? "#a1a1aa"
          : base.borderColor,
      },
      padding: "3px 0",
      "::placeholder": {
        color: error ? " #e11d48" : "",
      },
      backgroundColor: theme === "dark" ? "#3f3f46" : "#ffffff",
    }),
  };

  const inputOptions = useMemo(
    () =>
      options.map((option) => ({
        value: option,
        label: option,
      })),
    [options]
  );

  const handleSelectChange = (
    selected: SingleValue<Option> | MultiValue<Option>
  ) => {
    if (isMulti) {
      const values = (selected as MultiValue<Option>).map(
        (option) => option.value
      );
      onChange(values);
    } else {
      onChange((selected as Option).value);
    }
  };

  return (
    <div className="flex flex-col">
      <label
        htmlFor={id}
        className={`text-sm mb-0.5 font-medium ${
          error ? "text-rose-600" : "text-gray-900"
        }`}
      >
        {label}
      </label>
      <ReactSelect
        isClearable
        name={name}
        id={id}
        options={inputOptions}
        isMulti={isMulti}
        placeholder={placeholder}
        value={
          isMulti
            ? inputOptions.filter((option) =>
                (value as string[]).includes(option.value)
              )
            : inputOptions.find((option) => option.value === value)
        }
        onChange={handleSelectChange}
        styles={colorStyles}
      />
      {errorMsg && <small className="text-red-600 px-1">{errorMsg}</small>}
    </div>
  );
};

export default Select;

GenaeralInfo.tsx

"use client";

import DatePicker from "../Inputs/DatePicker";
import Input from "../Inputs/Input";
import Select from "../Inputs/Select";
import Tiptap from "../Tiptap";
import * as Yup from "yup";
import useCountries from "@/hooks/useCountries";
import useStates from "@/hooks/useStates";
import { useFormik } from "formik";
import { teams } from "@/constants";

const schema = Yup.object().shape({
  team: Yup.string().required("Team is required"),
  contractName: Yup.string().required("Contract Name is required"),
  country: Yup.string().required("Country is required"),
  state: Yup.string().required("State is required"),
  startDate: Yup.string().required("Start Date is required"),
  workDescription: Yup.string()
    .required("Work description are required")
    .min(50, "Work description should be at least 50 characters long")
    .max(200, "Work description can't exceed 200 characters"),
});

const GeneralInfo = () => {
  const countries = useCountries();

  const formik = useFormik({
    initialValues: {
      team: "",
      contractName: "",
      country: "",
      state: "",
      startDate: "",
      workDescription: "",
    },
    validationSchema: schema,
    onSubmit: (values, { resetForm }) => {
      console.log(values);
      resetForm();
    },
  });
  const isoCode = countries.find(
    (country) => country.name === formik.values.country
  )?.isoCode;
  const states = useStates(isoCode);

  return (
    <div className="w-full space-y-6">
      <Select
        label="Team"
        id="team"
        name="team"
        placeholder="Select team"
        options={teams.map((team) => team.name)}
        value={formik.values.team}
        onChange={(selectedOption) => {
          formik.setFieldValue("team", selectedOption);
        }}
        error={!!formik.errors.team}
        errorMsg={formik.errors?.team}
      />
      <Input
        id="contractName"
        name="contractName"
        label="Contract Name"
        placeholder="Contract for Product Design"
        value={formik.values.contractName}
        onChange={formik.handleChange}
        error={!!formik.errors.contractName}
        errorMsg={formik.errors.contractName}
      />

      <div className="grid grid-cols-2 gap-4">
        <Select
          label="Contractor's Country"
          id="country"
          name="country"
          placeholder="Select country"
          options={countries.map((country) => country.name)}
          value={formik.values.country}
          onChange={(selectedOption) => {
            formik.setFieldValue("country", selectedOption);
          }}
          error={!!formik.errors.country}
          errorMsg={formik.errors?.country}
        />
        <Select
          label="State"
          id="state"
          name="state"
          placeholder="Select team"
          options={states.map((state) => state.name)}
          value={formik.values.state}
          onChange={(selectedOption) => {
            formik.setFieldValue("state", selectedOption);
          }}
          error={!!formik.errors.state}
          errorMsg={formik.errors?.state}
        />
      </div>
      <DatePicker
        label="Start Date"
        id="startDate"
        name="startDate"
        placeholder="Select date"
        onChange={(date) => formik.setFieldValue("startDate", date)}
        value={formik.values.startDate}
        error={!!formik.errors.startDate}
        errorMsg={formik.errors?.startDate}
      />
      <Tiptap
        id="workDescription"
        name="workDescription"
        label="Work Description"
        value={formik.values.workDescription}
        onChange={(value) => {
          formik.setFieldValue("workDescription", value);
        }}
        errorMsg={formik.errors?.workDescription as string}
      />
      <button type="button" onClick={() => formik.handleSubmit()}>
        Submit
      </button>
    </div>
  );
};

export default GeneralInfo;

How do I style an “auto-complete-select”-Dropdown-List like an “abp-select”-Dropdown-List

I build a create-form for my application and used the tag-helpers

abp-select asp-for="MyModelField" 

(normal Dropdown-List with static option-values from Enum)
and

<select asp-for="MyOtherModelField"
        class="auto-complete-select"
        data-autocomplete-api-url="/api/app/lookup/my-function-name"
        data-autocomplete-display-property="name"
        data-autocomplete-value-property="id"
        data-autocomplete-items-property="items"
        data-autocomplete-filter-param-name="filter"
        data-autocomplete-allow-clear="true">
</select>  

(auto-complete List with values calculated with ajax-request)

The result of these two lines is this: the two different Dropdown-Lists

I now want the second Dropdown-List to look like the first.
Can anybody tell me some keywords to google for or maybe a short tutorial how to “copy the style”?

I tried to inspect the classes of the first Dropdown-List with the developer-tools in Chrome and add different classes to the autocomplete-select-tag (for example the class “form-select”). But nothing changed.

‘Webpack Module Not Found’ on pre-built docker image

I have a 3 docker images for a functioning website deployed on AWS. I have been recently asked to deploy this on new location and do some modifications to the frontend. However, this site hasn’t been supported or modified since 2020, which means that is a number of security updates and refactoring that needs to go into it.

To give the client some version of the site that they can play with, we decided to provide the currently deployed tool, but there is a catch: The client does not have an cloud infrastructure. To solve for that, we tested providing docker images to them along-side a docker compose script to deploy the application. The tests that we did worked well for some images, however I’m stuck with the frontend piece.

If I try to re-build the image, I end up with a blank website completely non-functional which I know is going to take a lot of time to solve. So, I extracted the image from AWS, but I get the error in the title when trying to deploy it.

For me its very weird, because I assume in a Kubernetes application such as this one you would need to consistently re-deploy the images as needed, and as such we should have any errors when trying to replicate the docker compose script.

Below is a complete traceback of the error, and the docker compose script. Would you know why this issue is happening and how to fix it?

Error traceback for the application

Docker Compose script:

version: '3.7'

volumes:
  mongo_data:


services:
  app-reload:
    image: stb-frontend:production-latest
    command: bash -c "npm run start:server"
    env_file: ./.env
    ports:
      - '9001:9001' # nodejs
      - '5858:5858' # nodejs debug
    volumes:
      - ./server:/home/node/app/server
      - ./client:/home/node/app/client
      - ./shared:/home/node/app/shared
      - ./config:/home/node/app/config
    depends_on:
      - app-client-reload
      - mongo
    networks:
      - db
      - python

  app-client-reload:
    image: stb-frontend:production-latest
    command: bash -c "npm run start:client"
    env_file: ./.env
    ports:
      - '9000:9000'
    volumes:
      - ./server:/home/node/app/server
      - ./client:/home/node/app/client
      - ./shared:/home/node/app/shared
      - ./config:/home/node/app/config
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:9000']
      interval: 30s
      timeout: 10s
      retries: 20
    networks:
      - db

  app:
    image: stb-frontend:production-latest
    command: bash -c "npm run start:server"
    env_file: ./.env
    ports:
      - '9001:9001' # nodejs
      - '5858:5858' # nodejs debug
    depends_on:
      - app-client
      - mongo
    networks:
      - db

  app-client:
    image: stb-frontend:production-latest
    command: bash -c "npm run start:client"
    env_file: ./.env
    ports:
      - '9000:9000' # webpack-dev-server port
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:9000']
      interval: 30s
      timeout: 10s
      retries: 20
    networks:
      - db

  mongo:
    image: stb-mongo:production-latest
    command: mongod --port 27017
    ports:
      - '27017:27017'
    volumes:
      - type: volume
        source: mongo_data
        target: /data/db
    networks:
      - db

how to get captions of unlisted youtube video

I am trying to get the caption of the youtube video which is unlisted. The video have auto Generated captions and I want that captions programmatically using nodejs.
the Things that i tried are Youtube data API – > the problems is always throws the error for the not founding the video. However when I try to list it it says the video is there, so ver skeptical about it.

async function getCaptions(videoId) {
  try {
    // List caption tracks for the given video ID
    const response = await youtube.captions.list({
      part: 'snippet',
      videoId: videoId,
    });

    const captions = response.data.items;
    if (!captions.length) {
      console.log('No captions found for this video.');
      return;
    }

    // Download the caption track (e.g., the first one)
    const captionId = captions[0].id;
    const captionTrack = await youtube.captions.download({
      id: captionId,
      tfmt: 'srt', // Use 'vtt' for WebVTT format or 'srt' for SubRip
    });

    console.log('Caption track:', captionTrack.data);
  } catch (error) {
    console.error('Error fetching captions:', error);
  }
}

getCaptions('video_id');
//when I run this i get the error 404 vide not found

async function checkVideoAccess(videoId) {
  try {
    const response = await youtube.videos.list({
      part: 'snippet',
      id: videoId,
    });

    if (response.data.items.length === 0) {
      console.log('Video not found or inaccessible.');
    } else {
      console.log('Video is accessible:', response.data.items[0].snippet.title);
    }
  } catch (error) {
    console.error('Error accessing video:', error);
  }
}

checkVideoAccess('video_id');
//when I run this i get video is accessible

I also tried scrapers-> the problem with scrapers is that the i do get the captions in my local env. but the moment i deploy it the aws ec2 instance, it stops working. I guess youtube is blocking the IP for my aws instance.

I have tried Youtube data api and scrapers and nothing is working for me. I would really appreciate any help. Also thoreo AI (website to summarize the youtube videos) is able to do generate the transcript for the unlisted youtube video. I dont know how they did that.

Z-index ignored while transitioning using the View Transitions API

Note: The example below uses the View Transitions API which is not yet supported in all browsers. In Firefox this code won’t do the transitions and thus will not show the problem I’m having.

What I’m trying to make
Using the View Transitions API I’m transitioning between 2 elements. This happens when the user clicks on an item, this will open a (sort of) modal over a list of items with a nice transition.

The problem I’m facing
The API doesn’t seem to respect the stacking order very well (z-index). The biggest problem is that the .overlay.backdrop is going over the element that is in a transition. Only when the transition is done you can see the item “light up” and go on to of the backdrop. I also cannot figgur out how to make the selected item go over the other items while in transition.

Tip: You can see really clear what is happing when you set the animation speed to 10% in the chrome devtools.

animtion-speed

What i tried

  1. Different ways of changing the structure of the DOM and z-index of items.
  2. Have been playing around with the ::view-transition-group (docs link) pseudo element in my CSS, but since I’m setting the names of my items dynamically i don’t think i can use this?

I really have no clue how to debug this more.

const { ref } = Vue;

const app = Vue.createApp({
  setup() {
    const items = [
      {
        id: 1,
        title: 'Diablo 4',
        description: 'A shit game with a decent story',
      },
      {
        id: 2,
        title: 'Elden Ring',
        description: 'A good game with a shit story',
      },
      {
        id: 3,
        title: 'The Witcher 3',
        description: 'A good game with a good story',
      },
      {
        id: 4,
        title: 'Cyberpunk 2077',
        description: 'A shit game with a shit story',
      },
    ];

    const activeItem = ref(null);

    const setActiveItem = (item) => {
      if (!document.startViewTransition) {
        activeItem.value = activeItem.value === item ? null : item;
        return;
      }

      document.startViewTransition(() => {
        activeItem.value = activeItem.value === item ? null : item;
      });
    };

    return {
      items,
      activeItem,
      setActiveItem
    };
  }
});

app.mount('#app');
.box {
  background-color: lightblue;
  cursor: pointer;
  position: relative;
  z-index: 1;
}

.box.small {
  padding: 1rem;
}

.box.big {
  padding: 2rem;
  font-size: 1.5rem;
  margin: 2rem;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  padding: 1rem;
}

.overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  z-index: 11;
}

.overlay.backdrop {
  view-transition-name: overlay;
  background: rgba(0, 0, 0, 0.5);
  z-index: 10;
}

body {
  margin: 0;
  display: grid;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.5.4/vue.global.min.js"></script>

<div id="app">
  <!-- Detail view (overlay) -->
  <div>
    <div class="overlay backdrop" v-if="activeItem"></div>
    <div class="overlay" v-if="activeItem" @click="setActiveItem(null)">
      <div class="box big" :style="{ viewTransitionName: `box-${activeItem.id}` }">
        <span :style="{ viewTransitionName: `title-${activeItem.id}` }">
          {{ activeItem.title }}
        </span>
        <p>{{ activeItem.description }}</p>
      </div>
    </div>
    <!-- List view -->
    <div class="grid">
      <div v-for="item in items" :key="item.id" class="box small" @click="setActiveItem(item)"
        :style="{ 
          viewTransitionName: activeItem?.id === item.id ? '' : `box-${item.id}`,
          visibility: activeItem?.id === item.id ? 'hidden' : 'visible',
        }">
        <span :style="{ viewTransitionName: activeItem?.id === item.id ? '' : `title-${item.id}` }">
          {{ item.title }}
        </span>
      </div>
    </div>
  </div>
</div>

Anyone here some ideas on how to fix this?

Vue CLI not re-rendering

I am facing this issue…

I am working on a project using Flask and Vue, and I am having trouble with the front end. I am using Vue Cli with Babel and router packages.

Now I am trying to make a vue view file.

  1. I start my server.

  2. make changes (e.g. changing some text, style, etc.)

  3. I am not able to see the changes without stopping the server and starting again manually. On average, it takes 5 to 20 minutes.

Is there a way for the Vue server to automatically update itself, as I code?

I am new to Vue, and this is for a college project. I am told that the server detects changes automatically and updates them, but that is not happening in my case.

I am sharing my config files here.

App.vue:

<template>
  <router-view/>
</template>

<style scoped>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

main.js:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

babel.config.js:

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ]
}

jsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "baseUrl": "./",
    "moduleResolution": "node",
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  }
}

pacakge.json:

`{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
  },
  "dependencies": {
    "core-js": "^3.8.3",
    "vue": "^3.2.13",
    "vue-router": "^4.0.3"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-router": "~5.0.0",
    "@vue/cli-service": "~5.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead",
    "not ie 11"
  ]
}
`

vue.config.js:

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true
})

I have created 3+ vue projects, but the result is the same, I am not sure what other dependencies to install.

Please help me out, thanks!

The site is not accessing cookies in Express. How can I set up CORS for it?

In a project, I am allowing users to log in and then add notes to a database using React and Express. Currently, I am hosting the client side on GitHub Pages and the server on Railway. Everything is working except the server can’t access cookies when checking for authentication to fetch notes.


//client side Login

const checkUser = await fetch(`https://onotesbackend-production.up.railway.app/login`, {

                credentials: 'include',

                headers: {

                    'Accept': 'application/json',

                    'Content-Type': 'application/json'

                },

                method: "POST",

                body: JSON.stringify(data)

            })

//client side feching

 const data = await fetch(`https://onotesbackend-production.up.railway.app/usernotes`, {

                credentials: 'include',

                method: "GET"

            });

//server side index.js page


const port = 3000



main().catch(err => console.log(err));



async function main() {

    await mongoose.connect("secreat");

}



const corsOptions = {

    origin: ["https://mrd9877.github.io", "http://localhost:3001"],

    credentials: true,

    methods: "GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE",

    allowedHeaders: ['Content-Type', 'Authorization', 'Content-Length', 'X-Requested-With', 'Origin', 'Accept'],

    optionSuccessStatus: 200,

}





app.use(cors(corsOptions))



app.use(express.json({

    type: ['application/json', 'text/plain']

}))

app.use(cookieParser())

app.use(session({

    secret: 'Super secret secret',

    resave: false,

    saveUninitialized: false,

    cookie: {

        maxAge: 60000 * 60,

        httpOnly: false,

        withCredentials: true,

        sameSite: 'None',

    },

    store: MongoStore.create({

        client: mongoose.connection.getClient()

    })

}))

app.use(passport.initialize())

app.use(passport.session())



app.use(router)





app.get('/', (req, res) => {

    res.send('Hello World!')

})



app.listen(port, () => {

    console.log(`Example app listening on port ${port}`)

})


//login router



const router = Router();



router.post("/login", async (req, res) => {

    const data = req.body

    const findUser = await NewUser.findOne({ username: data.username })

    if (!findUser) return res.sendStatus(401)

    if (findUser.password !== data.password) {

        res.sendStatus(401)

    }

    if (findUser.password === data.password) {

        req.session.user = findUser.id

        console.log("log in done")

        console.log(req.sessionId)

        res.sendStatus(200)

    }

})



export default router


//fech user notes router



const router = Router();

let userid = null



function isAuthenticated(req, res, next) {

    req.sessionStore.get(req.sessionID, async (err, sessionData) => {

        console.log(req.sessionID)

        if (err) {

            res.send({ "msg": "please login to use this service" }).status(401)

            return

        }

        if (sessionData !== null) {

            userid = await sessionData.user;

            next()

        } else {

            res.sendStatus(402)

        }



    })

}



router.get('/usernotes', isAuthenticated, async (req, res) => {

    const findUser = await NewUser.findById(userid)

    if (!findUser) {

        res.send({ "msg": "invalid user" }).status(401)

        return

    }

    const username = findUser.username

    const findUserNotes = await Notes.find({ username: username }).exec()

    res.send(findUserNotes)



})

I tried..




app.use((req, res, next) => {



    const isSecure = req.secure || req.headers['x-forwarded-proto'] === 'https';







    const cookieOptions = {



        secure: isSecure,      



        httpOnly: true,        



        sameSite: 'Lax',    



        maxAge: 24 * 60 * 60 * 1000



    };







    res.cookie('user_id', '12345', cookieOptions);



    next();



});



Need guidance on which tool is suitable to build an app/website whichever takes less time [closed]

I’m not a coder, but a management student. I have opted for a course Agile Software Development Methodology. Now Working on a college project to create a library book borrowing app/website(hosted or local server). I have a fixed list of users and books stored in Google Sheets.

Goal:
User Authentication: Users should log in using their roll number.
Book Inventory: The app should display a list of available books and their status (available/issued).
Book Borrowing Request: Users can select books and send a borrowing request(by clicking “send request button”) to the library via email.

Constraints:
Time: I have a tight deadline of 2-3 weeks.
Technical Expertise: I’m a beginner with limited to no coding experience.

What I have tried so far:
I have asked ChatGPT to help me with Google Sheets and MIT App Inventor, but somehow the .js code which was shared by GPT to link Google Sheets API to MIT App doesn’t work hence the app stands unusable.

Request:
I’m looking for guidance on the most efficient way to develop this app/website within the given constraints. I’m open to using no-code or low-code platforms to speed up the development process.

Specific Questions:

  1. Recommended No-Code/Low-Code Platforms: Which platforms are suitable for this project?
  2. Data Integration: How can I integrate Excel/Google Sheets data into the app?
  3. User Interface Design: What are the best practices for designing a user-friendly interface?
  4. Email Integration: How can I implement email functionality to send borrowing requests to the librarian?

Any advice and code snippets/cloud platforms/or anything else would be greatly appreciated. Please help.

Adjust element dimensions, including text size, according to available space

I have a very minimalistic interface that contains two areas: a submit button area and a content area. The entire interface should always be completely visible onscreen with the user never having to scroll to see everything. While the submit button should always occupy at least a certain amount of screenspace, the content area can have anywhere between 1 and several (lets say 8) elements.

These elements should share the rest of the available vertical screen space and scale according to it, including the text displayed inside them. Making elements grow and shrink with css-flex is usually available, using it does not adjust the font-size to allow the text to grow accordingly for readability.

Is this possible in pure css or do I need to calculate the available space of an element and use js to make adjustments to the elements on the fly depending on the amount of items and the available space?

A fiddle with an example for the layout: https://jsfiddle.net/xpyLz0rv/

This needs to look the same on all devices, and on all devices it needs to fit onscreen and be legible. Yes the content of the buttons are only letters and the only lengthy text is the submit button’s label.

Example:

.container {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.content-area {
  flex-grow: 1;
}

.content-area > * {
   /* ??? */
}

.submit-area {
  flex-grow: 0;
  height: 20%;
}
<div class="container">
    <div class="content-area">
        <button>A</button>
        <button>B</button>
        <button>C</button>
    </div>
    <div class="submit-area">
        <button>Send Choice</button>
    </div>
</div>

Why is my api data saying fulfilled but returning undefined?

I’m using the GameSpot API in my React Redux web app (set up with Vite). I’m seeing undefined data in my components, although Redux DevTools shows each query state as fulfilled with data visible there.

I’ve set up useEffect in App.jsx to merge fields from three endpoints each returning different data unique to that endpoint:

  • games (genres, release date)

  • reviews (scores)

  • releases (platforms, publishers, developers).

Here’s my setup:

App.jsx

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { useDispatch } from 'react-redux'
import { useEffect } from 'react'
import './App.css'
import { setGames } from './features/Games/gamesSlice'
import { useGetGamesQuery, useGetReviewsQuery, useGetReleasesQuery } from './api/gamespotApiSlice'
import { Header } from './features/Header/Header'
import { GamesList } from './features/Games/GamesList/GamesList'
import { GameDetails } from './features/Games/GameDetails/GameDetails'

function App () {
  const dispatch = useDispatch();
  const { data: gamesData } = useGetGamesQuery();
  const { data: reviewsData } = useGetReviewsQuery();
  const { data: releasesData } = useGetReleasesQuery();
  useEffect(() => {
    if (gamesData && reviewsData && releasesData) {
      const mergedData = gamesData.results.map(game => {
        const review = reviewsData.results.find(review => review.game.id === game.id);
        const release = releasesData.results.find(release => release.game_api_url.includes(game.name));
        const publisher = release && release.publishers.length > 0 ? release.publishers[0] : "Unknown";
        const developer = release && release.developers.length > 0 ? release.developers[0] : "Unknown";
        return {
            ...game,
            id: game.id,
            name: game.name,
            cover: game.image,
            platform: release ? release.platform : null,
            genres: game.genres || [],
            release_year: new Date(release ? release.release_date : null).getFullYear(),
            score: review ? review.score : null,
            publisher,
            developer
        };
      });
      const sortedGames = [...mergedData].sort((a, b) => b.score - a.score);
      dispatch(setGames(sortedGames));
    }
  }, [dispatch, gamesData, reviewsData, releasesData]);
  return (
    <Router>
      <Header />
      <main>
        <section className='game-view'>
          <Routes>
            <Route path='/games/:id' element={<GameDetails />} />
            <Route path='/' element={<GamesList />} />
          </Routes>
        </section>
      </main>
    </Router>
  );
}

export default App;

gamespotApiSlice.js

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

const API_KEY = '?api_key='+ import.meta.VITE_GAMESPOT_API_KEY;
const jsonFormat = '&format=json';

export const gamespotApi = createApi({
    reducerPath: 'gamespotApi',
    baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
    endpoints: (builder) => ({
        getGames: builder.query({
            query: () => `games/${API_KEY}${jsonFormat}`,
        }),
        getReviews: builder.query({
            query: () => `reviews/${API_KEY}${jsonFormat}&sort=score:desc`,
        }),
        getReleases: builder.query({
            query: () => `releases/${API_KEY}${jsonFormat}`,
        })
    })
})

export const {
    useGetGamesQuery,
    useGetReviewsQuery,
    useGetReleasesQuery
} = gamespotApi;

export default gamespotApi.reducer;

I’ve also tried simpler approaches (e.g., displaying setGames directly within useEffect without merging & filtering fields in the endpoint queries), but I still see undefined in components. Any advice on handling this data across endpoints or troubleshooting undefined data would be appreciated!

How to Complete PayPal Express Checkout in a Headless Shopware 6 Store Without Redirect to PayPal Confirmation?

I’ve implemented the PayPal Express Checkout for my headless Shopware 6 store following Shopware’s official example. However, I’m running into issues on the last step, where they use fetch() to call the redirectUrl. This approach doesn’t work for me because the redirectUrl response is HTML and triggering a fetch on it doesn’t redirect the user to PayPal as intended.

Here’s my current workaround: Instead of using fetch(), I redirect the user directly to the redirectUrl. This opens the PayPal interface again for a second confirmation and while it does mark the order as paid in Shopware, it adds unnecessary steps for the user.

How can I complete the PayPal Express Checkout flow without needing to redirect to the redirectUrl for a second confirmation at PayPal? What steps should I follow to mark the order as paid in Shopware after handlePayment without this extra redirect?

<PayPalScriptProvider
  options={{
    clientId: "<myClientId>",
  }}
>
  <PayPalButtons
    createOrder={async () => {
      // Create order --> PayPal
      // POST /store-api/paypal/express/create-order
      // return response.data.token
    }}
    onApprove={async (data, actions) => {
      // Prepare Checkout --> PayPal
      // POST /store-api/paypal/express/prepare-checkout { body: { token: data.orderId }}
      
      // Update context --> set paymentMethodId to PayPal
      // POST /store-api/account/register { body: { paymentMethodId: <paypalPaymentMethodId> }}
      
      // Create order --> Shopware
      // POST /store-api/checkout/order
      
      // Handle Payment --> Shopware/PayPal
      // POST /store-api/handlePayment 
      // { query: {isPayPalExpressCheckout: true, paypalOrderId: data.orderId } body: { orderId: <shopwareOrderId>, finishUrl: 'https://...', errorUrl: 'https://...' } }
      
      // Redirect to the redirectUrl from the handlePayment endpoint --> re-confirmation at PayPal
    }}
  ></PayPalButtons>
</PayPalScriptProvider>

In this setup, redirecting to the redirectUrl after handlePayment opens PayPal again, prompting the user to confirm the payment a second time. Only after this second confirmation does Shopware mark the order as “paid” instead of “unconfirmed.”

Calling function wrapped in useCallback from useEffect updates state too many times

After coming back from Vue land I find myself suddenly back in React land and my usage of hooks so far haven’t gotten passed the basic stages until today where I found myself trying to update multiple states when the depecendy mapped for useEffect changes

So basically my thought was to implement a Blackjack hook, for starters it will just be client side and that might be putting me into some problems I shouldn’t face if I had the backend done. But I still want to learn what I can do to avoid this in the future my hook has these functions:

  const drawDealerCard = useCallback(() => {
    console.log("drawDealerCard");
    setDeck((prevDeck) => {
      const deckCopy = [...prevDeck];
      const newCard = deckCopy.pop();

      console.log("setDeck");
      setDealerHand((prevHand) => {
        console.log("setDealerHand");
        return [...prevHand, newCard!];
      });

      return deckCopy;
    });
  }, []);

  useEffect(() => {
    if (!isDealerHidden) {
      console.log("useEffect isDealerHidden changed");
      drawDealerCard();
    }
  }, [isDealerHidden, drawDealerCard]);

When isDealerHidden changes to false I want to call the drawDealerCard function. I put it outside because I have this useEffect that deals a new card when the dealer hasn’t reached a high enough score

    if (!isDealerHidden && dealerHand.length >= 2) {
      const dealerScore = calculateScore(dealerHand as PlayingCard[]);
      console.log("Dealer hand", dealerHand);
      console.log("Dealer score", dealerScore);
      setDealerScore(dealerScore);

      if (parseInt(dealerScore) < 17) {
        setTimeout(() => {
          //drawDealerCard();
        }, 1000);
      }
    }
  }, [dealerHand, isDealerHidden, drawDealerCard]);

I have not come to any errors with this yet.

But my problem is from the first code that the “setDeck” state update is running twice, as i get double the console output and the setDealerHand in turn is logged 4 times. How do I avoid this as this would give the “Dealer” 3 cards with the new card duplicated and not the expected 2.