How can I prevent my list component from remounting when using modal routes with HashRouter in React Router v5?

I’m adjusting some functionality for a React app (using React 16.13.1) with React Router v5 and HashRouter. My app displays a list of coupons in a table (using AgGrid) within a component (named Coupons). When a user clicks on a coupon row, I want to open a modal with the coupon details without unmounting the underlying list so that its scroll position and state are preserved.

To achieve this, I’m using the “modal route” pattern. In my Coupons component, my rowClicked handler looks like this:

rowClicked = e => {
  console.log("Current path is", this.props.location);
  this.props.history.push({
    pathname: `/${this.state.objects}/${e.data.id}`, // e.g., "/coupons/3747"
    state: { background: this.props.location },
  });
};

Here, this.state.objects is “coupons”, and this.props.location (from withRouter) shows:

{ pathname: '/coupons', search: '', hash: '', state: undefined }

In my DefaultLayout component, I use a <Switch> with a custom location prop:

const location = useLocation();
const background = location.state && location.state.background;

<Suspense fallback={loading()}>
  <Switch location={ background || location }>
    {routes.map((route, idx) => (
      <Route
        key={idx}
        path={route.path}
        exact={route.exact}
        render={(props) => {
          console.log("[Switch] Matched route:", route.path);
          console.log("[Switch] location used:", background || location);
          return <route.component {...props} />;
        }}
      />
    ))}
    <Redirect from="/" to="/users" />
  </Switch>
</Suspense>

{background && (
  <Route path="/coupons/:id">
    <ModalRouteForCoupons />
  </Route>
)}

My logs indicate that when I click on a coupon, the location becomes:

location: { pathname: '/coupons/3747', ... }
background: { pathname: '/coupons', ... }

So the <Switch> uses the background (i.e. /coupons), and it correctly matches the route for the list. Additionally, a separate <Route> renders my modal (ModalRouteForCoupons).

export default function ModalRouteForCoupons() {
  const { id } = useParams();
  const history = useHistory();

  const closeModal = () => {
    history.goBack();
  };

  console.log(id);

  return (
    <Modal isOpen={true} toggle={closeModal} size="lg">
      <ModalHeader toggle={closeModal}>Редактирование купона</ModalHeader>
      <ModalBody>
        <Coupon
          isEmbedded={true}
          match={{ params: { id } }}
          done={closeModal}
        />
      </ModalBody>
    </Modal>
  );
}

However, the problem is that when I click a row, my list component (Coupons) unmounts and then remounts (I see “Coupons unmount!” and then “mount” logs from the component). This causes the scroll position to reset and data to reload—something I want to avoid.

Additional details:

  • My routes.js includes both a route for /coupons (rendering the list)
    and /coupons/:id (rendering the coupon detail).
  • I’m using HashRouter, and my logs show that location.key is
    undefined.
  • I’ve confirmed that in the rowClicked method,
    this.props.location.pathname is /coupons, so background is set
    correctly.

My questions:

  1. Why does React Router remount the Coupons component (i.e. my list)
    when I navigate to /coupons/3747 with a background state, even
    though my is set to use background || location?

  2. Is this behavior due to using HashRouter (which might not provide a
    unique location key), or is it something in my route configuration?

Any insights or suggestions on how to prevent the list from remounting (thus preserving its scroll position and internal state) while still having a modal that shows the coupon detail (with the URL reflecting /coupons/:id) would be greatly appreciated!

Vue 3 + Vue I18n: “Not found key” error only on one page, works fine elsewhere

Issue Overview
I’m using Vue 3 and Vue I18n (version 9.x) in my project. All of my pages are translating keys correctly except for one page, where it fails to find the translation keys for sustainabilityPage. I keep seeing console warnings like:

[intlify] Not found 'sustainabilityPage.sections.rAndD.title' key in 'tr' locale messages.
[intlify] Fall back to translate 'sustainabilityPage.sections.rAndD.title' key with 'en' locale.

Despite the fact that I have sustainabilityPage definitions in my tr.json (and en.json) files, it just won’t translate on this page.

Vue I18n Configuration (i18n.js)
import { createI18n } from 'vue-i18n';
import tr from './locales/tr.json';
import en from './locales/en.json';

const i18n = createI18n({
  legacy: false, // for Vue 3 Composition API
  locale: 'tr',  // default language
  fallbackLocale: 'en',
  globalInjection: true,
  messages: {
    tr,
    en
  }
});

export default i18n;

Main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import i18n from './i18n';

const app = createApp(App);
app.use(i18n); // using Vue I18n
app.use(router);
app.mount('#app');

Problematic Component (Sürdürülebilirlik.vue)

<template>
  <div
    class="about-page"
    :style="{ backgroundImage: 'url(/assets/img/fabrika.jpg)' }"
  >
    <div class="overlay"></div>
    <div class="container mx-auto px-4 py-12">
      <!-- Section 1 - Ar-Ge Merkezi -->
      <div class="flex flex-wrap items-center mb-12 fade-in">
        <div class="w-full md:w-5/12 ml-auto mr-auto px-4">
          <div class="card">
            <h3 class="text-2xl font-semibold text-white">{{ $t("sustainabilityPage.sections.rAndD.title") }}</h3>
            <p class="mt-4 text-lg leading-relaxed text-gray-200">
              {{ $t("sustainabilityPage.sections.rAndD.description1") }}
            </p>
            <p class="mt-4 text-lg leading-relaxed text-gray-200">
              {{ $t("sustainabilityPage.sections.rAndD.description2") }}
            </p>
          </div>
        </div>
        <div class="w-full md:w-4/12 ml-auto mr-auto px-4">
          <img
            src="/assets/img/resim2.jpg"
            :alt="$t('sustainabilityPage.sections.rAndD.title')"
            class="max-w-full rounded-lg shadow-xl transform transition duration-500 hover:scale-105"
            loading="lazy"
          />
        </div>
      </div>

      <!-- Section 2 - Yenilenebilir Enerji -->
      <div class="flex flex-wrap items-center mb-12 flex-row-reverse fade-in">
        <div class="w-full md:w-5/12 ml-auto mr-auto px-4">
          <div class="card">
            <h3 class="text-2xl font-semibold text-white">{{ $t("sustainabilityPage.sections.renewableEnergy.title") }}</h3>
            <p class="mt-4 text-lg leading-relaxed text-gray-200">
              {{ $t("sustainabilityPage.sections.renewableEnergy.description1") }}
            </p>
            <p class="mt-4 text-lg leading-relaxed text-gray-200">
              {{ $t("sustainabilityPage.sections.renewableEnergy.description2") }}
            </p>
          </div>
        </div>
        <div class="w-full md:w-4/12 ml-auto mr-auto px-4">
          <img
            src="/assets/img/resim3.jpg"
            :alt="$t('sustainabilityPage.sections.renewableEnergy.title')"
            class="max-w-full rounded-lg shadow-xl transform transition duration-500 hover:scale-105"
            loading="lazy"
          />
        </div>
      </div>

      <!-- Section 3 - Atık Su Arıtma -->
      <div class="flex flex-wrap items-center mb-12 fade-in">
        <div class="w-full md:w-5/12 ml-auto mr-auto px-4">
          <div class="card">
            <h3 class="text-2xl font-semibold text-white">{{ $t("sustainabilityPage.sections.wasteWaterTreatment.title") }}</h3>
            <p class="mt-4 text-lg leading-relaxed text-gray-200">
              {{ $t("sustainabilityPage.sections.wasteWaterTreatment.description1") }}
            </p>
            <p class="mt-4 text-lg leading-relaxed text-gray-200">
              {{ $t("sustainabilityPage.sections.wasteWaterTreatment.description2") }}
            </p>
          </div>
        </div>
        <div class="w-full md:w-4/12 ml-auto mr-auto px-4">
          <img
            src="/assets/img/resim4.jpg"
            :alt="$t('sustainabilityPage.sections.wasteWaterTreatment.title')"
            class="max-w-full rounded-lg shadow-xl transform transition duration-500 hover:scale-105"
            loading="lazy"
          />
        </div>
      </div>

      <!-- Section 4 - Enerji Üretimi -->
      <div class="flex flex-wrap items-center mb-12 flex-row-reverse fade-in">
        <div class="w-full md:w-5/12 ml-auto mr-auto px-4">
          <div class="card">
            <h3 class="text-2xl font-semibold text-white">{{ $t("sustainabilityPage.sections.energySolutions.title") }}</h3>
            <p class="mt-4 text-lg leading-relaxed text-gray-200">
              {{ $t("sustainabilityPage.sections.energySolutions.description1") }}
            </p>
            <p class="mt-4 text-lg leading-relaxed text-gray-200">
              {{ $t("sustainabilityPage.sections.energySolutions.description2") }}
            </p>
          </div>
        </div>
        <div class="w-full md:w-4/12 ml-auto mr-auto px-4">
          <img
            src="/assets/img/resim7.jpg"
            :alt="$t('sustainabilityPage.sections.energySolutions.title')"
            class="max-w-full rounded-lg shadow-xl transform transition duration-500 hover:scale-105"
            loading="lazy"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { useHead } from '@vueuse/head';
export default {
  name: "Sürdürelebilirlik",
  setup() {
    useHead({
      title: 'Kahramanmaraş Kâğıt - Ar-Ge ve Sürdürülebilirlik Çözümleri',
      meta: [
        { name: 'description', content: 'Kahramanmaraş Kâğıt olarak, Ar-Ge merkezi, yenilenebilir enerji yatırımları, atık su arıtma tesisimiz ve biyokütle enerji tesisimizle çevre dostu ve sürdürülebilir çözümler sunuyoruz.' },
        { name: 'keywords', content: 'Kahramanmaraş Kağıt, Ar-Ge Merkezi, Biyokütle Enerji Tesisi, Atık Su Arıtma, Sürdürülebilir Enerji, Güneş Panelleri, Yenilenebilir Enerji, Enerji Verimliliği, Çevre Dostu Üretim' },
        { property: 'og:title', content: 'Kahramanmaraş Kâğıt - Çevre Dostu ve Yenilikçi Çözümler' },
        { property: 'og:description', content: 'Yüksek enerji verimliliği ve çevre dostu teknolojilerle sürdürülebilir üretim yapıyoruz. Tesisimizde yenilikçi enerji çözümleri uyguluyoruz.' },
        { property: 'og:image', content: '/assets/img/fabrika.jpg' },
        { property: 'og:type', content: 'website' },
        { property: 'og:url', content: 'https://kahramanmaraskagit.com/surdurulebilirlik' },
        { name: 'twitter:card', content: 'summary_large_image' },
        { name: 'twitter:title', content: 'Kahramanmaraş Kâğıt - Sürdürülebilir Enerji ve Ar-Ge Çalışmaları' },
        { name: 'twitter:description', content: 'Ar-Ge merkezimiz ve enerji üretim tesislerimizle fark yaratıyoruz.' },
        { name: 'twitter:image', content: '/assets/img/resim2.jpg' },
        { name: 'viewport', content: 'width=device-width, initial-scale=1.0' }
      ]
    });
  }
};
</script>

<style scoped>
.about-page {
  position: relative;
  min-height: 100vh;
  background-size: cover;
  background-position: center center;
  background-attachment: fixed;
  color: white;
  overflow: hidden;
}

.overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.4);
  z-index: 1;
}

.container {
  margin-top: 100px;
  position: relative;
  z-index: 2;
}

.card {
  background-color: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
  border-radius: 10px;
  padding: 20px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}

img:hover {
  transform: scale(1.05);
  transition: transform 0.3s ease;
}

.fade-in {
  opacity: 0;
  animation: fadeInUp 1s ease-in-out forwards;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
</style>

Note: On other pages, $t(“someKey”) works perfectly. Only this page triggers “Not found” fallback warnings.

en.json

{
    "navbar": {
      "home": "Home",
      "corporate": "Corporate",
      "aboutUs": "About Us",
      "missionVision": "Mission and Vision",
      "products": "Products",
      "quality": "Quality",
      "sustainability": "Sustainability",
      "contact": "Contact",
      "career": "Career",
      "mediaCenter": "Media Center",
      "catalog": "E-Catalog"
    },
    
        "header": {
          "welcomeTitle": "Welcome to Kahramanmaraş Kağıt",
          "welcomeMessage": "Our company plays a significant role in the paper and packaging industry in Turkey. This position has been achieved over the years through the trust of our customers, suppliers, and employees."
        },

        "features": {
          "title1": "High-Quality Production",
          "desc1": "Kahramanmaraş Paper stands as a leader in the industry by producing paper under high quality standards. With an eco-friendly approach, we offer solutions that are conscious of the environment.",
      
          "title2": "Sustainability-Focused Production",
          "desc2": "Environmental awareness lies at the core of our business. The raw material we use in our factory is sourced entirely from 100% recycled waste paper. Thus, we help protect 6,000 hectares of forest area each year. We reinforce our commitment to the environment through advanced wastewater treatment systems and eco-friendly production processes at our facility.",
      
          "title3": "Building a Strong Future Together",
          "desc3": "At Kahramanmaraş Paper, we are not just producing paper; we are building a sustainable future with eco-friendly technologies. We continue to make a difference in the industry through our contributions to the regional economy, employment opportunities, and logistical advantages.",
      
          "title4": "Advanced Technology and R&D",
          "desc4": "For us, innovation is not only a goal but also part of our continuous development. Our R&D center works tirelessly to expand our product range and offer more innovative solutions to our customers. Every process in our factory is carried out in accordance with quality and safety standards.",
      
          "sectionTitle": "Working with Us Is a Privilege",
          "sectionDesc1": "At Kahramanmaraş Paper, we always prioritize customer satisfaction by adhering to the principle of providing high-quality products and services. We aim to build a long-term business partnership with you.",
          "sectionDesc2": "To learn more about our products, feel free to get in touch with us.",
          "sectionButton": "Get in Touch!",
      
          "quoteTitle": "Production with Evolving Technology",
          "quoteDesc": "By integrating technology into our production processes, we strengthen our competitive edge in the industry. We always strive to offer better and more efficient solutions."
        },

      
          "anafooter": {
            "companyName": "Kahramanmaraş Paper",
            "companyTagline": "Serving you with our Innovative and Eco-Friendly Approach.",
            "email": "[email protected]",
            "usefulLinks": "Useful Links",
            "home": "Home",
            "about": "About Us",
            "products": "Products",
            "equalOpportunities": "Equal Opportunities",
            "certificates": "Our Certificates",
            "contact": "Contact",
            "contactLocations": "Contact & Locations",
            "locationKahramanmaras": "Kahramanmaraş",
            "locationIstanbul": "Istanbul",
            "copyright":
              "© {year} Kahramanmaraş Paper Ind. and Trade Inc. All rights reserved.",
            "cookiePolicy": "Cookie Policy",
            "personalDataProtection": "Personal Data Protection",
            "informationSocietyServices": "Information Society Services",
            "cookiePreferences": "Cookie Preferences"
          },

          "about": {
    "pageTitle": "About Us",
    "paragraph1": "Kahramanmaraş Paper Industry and Trade Inc. was established in 1988 in Kahramanmaraş on an area of 200,000 m², of which 30,000 m² is enclosed.",
    "paragraph2": "Production of corrugated cardboard paper began at the end of 1989, with the PM1 paper machine that has an annual capacity of 40,000 tons.",
    "paragraph3": "In 1997, after investing in the PM2 paper machine, the company also began producing grey board. Later that same year, modernization of the PM1 paper machine not only improved quality ....,
    "paragraph4": "Since its foundation, Kahramanmaraş Paper has stood out by delivering solutions for the corrugated cardboard sector. Today, it serves domestic and international markets with Fluting, Test Liner, Grey Board, Plasterboard Paper, and various specialty paper grades.",
    "paragraph5": "Continuous operations in our R&D Center form a key dynamic of our growth. Under the principle of Total Quality, we pursue activities aimed at meeting the ....
      },
       
      "visionMission": {
        "pageTitle": "Our Mission and Vision",
    
        "mission": {
          "title": "Our Mission",
          "desc": "To recover waste paper from the environment and contribute to leaving a better world for future generations, while utilizing high technology and modern ....
        },
    
        "vision": {
          "title": "Our Vision",
          "desc": "To transform our company into an exemplary leader in the paper industry, one that adopts reliability, respectability, and customer satisfaction as its fundamental ....
        },
    
        "missionImageAlt": "Eco-friendly production mission image",
        "visionImageAlt": "Green production and zero waste vision image"
      },
      
      "footer": {
            "companyName": "Kahramanmaraş Paper",
            "companyTagline": "Serving you with our Innovative and Eco-Friendly Approach.",
            "email": "[email protected]",
            "usefulLinks": "Useful Links",
            "home": "Home",
            "about": "About Us",
            "products": "Products",
            "equalOpportunities": "Equal Opportunities",
            "certificates": "Our Certificates",
            "contact": "Contact",
            "contactLocations": "Contact & Locations",
            "locationKahramanmaras": "Kahramanmaraş",
            "locationIstanbul": "Istanbul",
          },
      
          "productsPage": {
            "title": "Our Products"
          },

          "qualityPage": {
            "sectionTitles": {
              "politikalar": "Our Policies",
              "ilkeler": "Our Principles",
              "eys": "Integrated Management System (IMS) Policy",
              "sosyal": "Social Compliance",
              "firsat": "Equal Opportunity",
              "sertifika": "Our Certificates"
            },
            "ilkeler": {
              "introHtml": "As Kahramanmaraş Paper Industry and Trade Inc., we carry out our activities within the framework of the core principles and values we embrace; with our focus on innovation....
              "listItems": [
                "Being a trusted company",
                "Continuously improving our processes and services",
                ...
                "Adhering to social responsibility and universal ethical values",
                "Giving importance to continuous training and development at every level",
                "Being a fast, agile, successful, results-oriented, and industrious company",
                "Setting an example for the best business practices in the paper industry",
                "Offering the best to our customers as quickly as possible with a ...
                "Being open to continuous improvement by tracking innovations and producing innovative products and ideas",
                "Carrying out deep-rooted, tradition-based corporate values on the basis of fairness, transparency, and mutual trust",
                ....
            },
            "eys": {
              "introHtml": "Kahramanmaraş Paper Industry and Trade Inc. acknowledges that the success of its activities is highly dependent on the quality, occupational health and safety, environment, and energy management systems it implements. Therefore, Integrated Management Systems will always be prioritized.",
              "paragraphs": [
                "As one of the leading players in the paper industry in our country, we aim to add value to all our stakeholders and contribute to sustainable development by conducting our paper production and trade activities in accordance with international standards.",
                "Our company, in line with its Quality, Environmental, Occupational Health and Safety, and Energy Management Systems, is committed to the following policies:"
              ],
              "listItems": [
                "Complying with legal and other requirements",
                "Ensuring continuous customer satisfaction",
                "Sustaining continuity and sustainability in all operations",
                "Supporting and improving suppliers and business partners",
                "Taking measures to enhance energy efficiency and conservation",
                "Constantly improving production efficiency and overall performance",
                "Respecting people and the environment by focusing on sustainability",
                "Ensuring effective, economical, and efficient use of all resources",
                "Providing necessary knowledge and resources to achieve set goals and objectives",
                "Preventing pollution, reducing waste, and increasing recycling rates",
                "Eliminating hazards, effectively managing risks and opportunities",
                "Creating an open communication environment for employee participation",
                "Complying with applicable legal and other requirements regarding energy efficiency, usage, and consumption",
                "Enhancing collaboration and transparency among stakeholders",
                "Considering quality, OHS, environmental, and energy performance in all design and procurement processes",
                "Implementing and continuously improving the ISO 9001, ISO 14001, ISO 45001, and ISO 50001 standards",
                "Structuring the Integrated Management System based on risk-based thinking, ensuring sustainability",
                "Providing comprehensive training to enhance awareness of all IMS-related standards",
                "Prioritizing the health and safety of employees over profitability, working towards a 'zero accident' goal"
              ],
              "chairmanLine": "Chairman of the Board: Muhammet Muhittin CİĞER"
            },
            "sosyal": {
              "introHtml": "<strong>As KAHRAMANMARAŞ PAPER IND. AND TRADE INC.,</strong>",
              "paragraphs": [
                "Our social compliance policy includes standards that we have created in collaboration with all our business partners based on fundamental principles and values, and implemented as a team effort. Our goal is to integrate the Social Compliance Policy into our corporate culture. Therefore, social compliance standards have been established and put into practice.",
                "In addition to creating products and services through these social compliance standards, this policy commits to providing employees with all rights derived from legal standards, complying with occupational health and safety rules, being environmentally conscious, and fostering an open and honest communication environment where employees feel valued and respected.",
                "The social compliance policy is communicated to all our employees through training sessions or communication channels (notice boards, website, email groups, etc.). Our suppliers are informed,.......
                "The Social Compliance Policy includes the following components:"
              ],
              "listItems": [
                "Prevention of Child Labor",
                "Prevention of Forced and Compulsory Labor",
                "Ensuring Occupational Health and Safety and Its Sustainability",
                "Respect for Freedom of Association, Representation, and Collective Bargaining Rights",
                "Prevention of Discrimination (Equal Treatment Approach)",
                "Recruitment and Regular Employment",
                "Prevention of Discipline, Harassment, and Ill-Treatment",
                "Raising Employee Awareness",
                "Communication of Requests and Complaints",
                "Working Hours",
                "Wages and Payments",
                "Compliance with Laws and Other Obligations",
                "Anti-Bribery and Corruption",
                "Supply Chain Management"
              ],
              "closingParagraph": "Kahramanmaraş Paper Ind. and Trade Inc. undertakes to carry out its social compliance activities in accordance with the applicable laws and regu....
              "chairmanLine": "Chairman of the Board: Muhammet Muhittin CİĞER"
            },
            "firsat": {
              "introHtml": "<strong>As KAHRAMANMARAŞ PAPER INDUSTRY AND TRADE INC., we value equal opportunity and diversity.</strong>",
              "paragraphs": [
                "Kahramanmaraş Paper Industry and Trade Inc. Equal Opportunity Policy defines our company's responsibilities and principles regarding equal opportunity applications, covering all employees and activities. Our company is aware of the great benefits of understanding, evaluating, and effectively managing differences at the individual, team, and corporate levels in achieving success."
              ],
              "listItems": [
                "Our organization respects human rights and upholds the principle of equality for all employees.",
                "In all human resources applications, including recruitment, promotion, and development decisions, we do not discriminate based on religion, language, race, or ethnic origin, and we prioritize collective intelligence within the company.",
                "We stand against any form of discrimination or harassment directed at our employees or occur.....
                "We do not discriminate based on gender, religion, sect, race, marital status, political opinion, disability status, social class, philosophical beliefs, or other visible or invisible....
                "We aim to increase the employment rate of women within the company and in managerial positions and strive to ensure gender equality at every management level.",
                "By fostering a high-performance culture, we support employees' professional and personal development through continuous education and feedback.",
                "We adopt an 'Equal Pay for Equal Work' policy and monitor related indicators.",
                "We promote the principle of equal opportunity among all employees through various training programs and social responsibility projects.",
                "Kahramanmaraş Paper strives to ensure that the Equal Opportunity Policy is communicated to all stakeholders.",
                "The Human Resources Department and Managers are responsible for tracking compliance with every aspect of the Equal Opportunity Policy at Kahramanmaraş Paper."
              ],
              "chairmanLine": "Chairman of the Board: Muhammet Muhittin CİĞER"
            },
            "sustainabilityPage": {
            "title": "R&D and Sustainability Solutions",
            "sections": {
              "rAndD": {
                "title": "Our R&D Center",
                "description1": "Our R&D Center was registered as Turkey's 576th R&D Center by the Ministry of Industry and Technology on December 13, 2017. A team of approximately 25 experts in six different departments conducts studies in process development, product innovation, energy efficiency, and intellectual property.",
                "description2": "By collaborating with universities and other R&D centers, we have successfully completed many national and international projects, such as TÜBİTAK projects, leading technical and technological developments."
              },
              "renewableEnergy": {
                "title": "Our Renewable Energy Investments",
                "description1": "As Kahramanmaraş Paper, we invest in renewable energy sources as part of our environmentally friendly production approach. Thanks to the solar panels installed at our factory facilities, we meet a significant portion of our energy needs using environmentally friendly and sustainable methods.",
                "description2": "This system optimizes energy costs, enabling us to achieve more efficient production. With our future projects, we will continue to support environmental sustainability."
              },
              "wasteWaterTreatment": {
                "title": "Our Wastewater Treatment Facility",
                "description1": "We prioritize the efficient use of water resources by adopting an environmentally friendly production approach in our factory. At our wastewater treatment facility, water generated from our production processes is treated using modern methods and reused in production.",
                "description2": "Thus, we reduce our reliance on natural water resources and contribute to environmental sustainability. Through continuous improvement and innovative technologies, we strive to make the most efficient use of our resources."
              },
              "energySolutions": {
                "title": "Innovative Solutions in Energy Production",
                "description1": "Our Kahramanmaraş factory is not only a production facility but also a plant that generates its own energy. Our 11 MW cogeneration plant provides the energy needed for our production processes, reducing our dependence on external sources.",
                "description2": "Additionally, our newly commissioned biomass energy plant significantly contributes to our factory’s environmental sustainability goals. By producing energy from organic waste, we both reduce our carbon footprint and adopt an environmentally friendly approach."
              }
            }
          } 
        }      
}

What I’ve Tried
Verified that all other pages correctly pick up $t(“…”) keys.
Inserted a console.log(“Testing key:”, this.$t(“…”)); in mounted(), which returns undefined or “Not found… key in ‘tr’ locale messages.”
Checked that tr.json does contain sustainabilityPage exactly as above.
Also tried console-logging window.i18n?.global.messages.value.tr, which shows undefined on this route, but not on others.
I’m using Options API on this component; my other components also use Options API and $t().

Question
Why does only this page fail to recognize sustainabilityPage.sections.rAndD.title while all other pages use $t() with no issues?
Could there be a route or instance conflict that means this component is not using the same i18n instance?
Any possible hidden reason that $t(“sustainabilityPage…”) can’t be found here?
Thanks in advance for your suggestions!

Typescript Code works in debug mode but not working normal mode

On debut mode code is working properly but on Proper run code run once and stop

const leftArrow = document.querySelector('.arrow-left');
   const rightArrow = document.querySelector('.arrow-right');
   const tabsWrapper = document.querySelector('.tabs-wrapper');
   const tabs = document.querySelector('.tabs');

      for (var i = 0; i < tabs.childElementCount; i++) {
        if (tabs.children[i].className != "Active") {
          tabsWrapper.scrollBy({
            left: 200, // Scroll right by 200px
            behavior: 'smooth'
          });
          
        }
        else {
          break;
          }
      }

          <div class="tabs-wrapper">
  <ul id="Custom-large-tabs" class="nav nav-tabs tabs">

    <li  class="tab active"><a id="aMain" data-target="#home" (click)="invalidateMain()" data-toggle="tab">Main  </a></li>
    <li ><a id="aFunding" data-target="#futureFunding" (click)="showfutureFundingGD()" data-toggle="tab">Funding  </a></li>
    <li ><a id="aLiability" data-target="#LiabilityTab" (click)="invalidateLiabilitiesTab()" data-toggle="tab">Liabilities </a></li>
    <li ><a id="aAdjustedTotalCommitment" data-target="#DealAdjustedtotalCommitment" (click)="invalidateDealAdjustedTab()" data-toggle="tab">Commitment  </a></li>
    <li><a id="aReservetab" data-target="#reserveTab" (click)="invalidateReserveTab()" data-toggle="tab">Reserves  </a></li>
    <li ><a id="aFeeInvoicetab" data-target="#FeeInvoicetab" (click)="invalidateFeeInvoicetab()" data-toggle="tab">Invoices </a></li>
    <li><a id="aDealAmorttab" data-target="#DealAmorttab" (click)="invalidateDealAmorttab()" data-toggle="tab">Amort </a></li>
    <li><a id="aNotepayrule" data-target="#notepayrule" (click)="shownotepayruleGD()" data-toggle="tab">Payrules </a></li>
    <li><a id="aMaturitytab" data-target="#Maturitytab" (click)="invalidateMaturitytab()" data-toggle="tab">Maturity </a></li>
    <li><a id="aAccountingtab" data-target="#AccountingClose" (click)="invalidateAccountingClose()" data-toggle="tab">Accounting Close</li>
    <li><a id="aServicingWatchlisttab" data-target="#ServicingWatchlist" (click)="invalidateServicingWatchlist()" data-toggle="tab">Distressed </a></li>
    <li><a id="aXIRRTab" data-target="#XIRRTab" (click)="GetXIRROutputByObjectID()" data-toggle="tab">XIRR</a></li>
    <li><a id="aPrepaymentPremiumtab" (click)="GetAllFeeType()" data-target="#PrepaymentPremiumtab" data-toggle="tab">Prepayment Premium  </a></li>
    <li><a id="aRulestab" data-target="#Rulestab" (click)="invalidateRulestab()" data-toggle="tab">Rules </a></li>
    <li><a id="aPayOff" data-target="#Payofftab" (click)="getPayoffData()" data-toggle="tab">Payoff </a></li>
    <li><a id="aImport" data-target="#docImport" (click)="showDocImport()" data-toggle="tab">Documents </a></li>
    <li ><a id="aActivitytab" data-target="#Activitytab" (click)="getDealActivity()" data-toggle="tab">Activity</a></li>

  </ul>
</div>

I am having multiple tabs and auto slide according to condition

Issue with Local annotations in sap fiori custom app

I am trying to create fiori local annotations in my project, I have added the annotations like below

enter image description here

And updated this code in annotations folder. Also i have modifed the manifest file to call this annoations file.
enter image description here

I am not getting any error and even in network tab the file loaded without any issue but fields are not coming in the smart table.
enter image description here

Can someone please throw some light on this ?

also added the initialvisiblefields property in smart table but still no luck.

How to create a 3d Rugby ball with 2 different images on it’s subsequent faces using ThreeJS and React Three Fiber

I’m trying to create a 3d rugby ball using ThreeJS and RTF and I’m struggling to create 4 faces on the ball where two subsequent faces on the ball will have two different images. Something similar to this.

I have been able to create the geometry and add one image on one face. But the other 3 images don’t show up on the geometry.

This is the code that I have so far:

import React, { Suspense } from "react";
import { Canvas, useLoader } from "@react-three/fiber";
import {
  OrbitControls,
  useProgress,
  Html,
} from "@react-three/drei";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import * as THREE from "three";

const RugbyBall: React.FC = () => {
  // Load textures
  const one = useLoader(THREE.TextureLoader, "/images/one.jpg");
  const two = useLoader(THREE.TextureLoader, "/images/two.jpg");
  const texture = useLoader(THREE.TextureLoader, "/images/texture.jpg");

  // Create materials
  const oneMaterial = new THREE.MeshPhysicalMaterial({
    map: one,
    bumpMap: texture,
    bumpScale: 1,
    roughness: 1,
    metalness: 0,
    // side: THREE.FrontSide,
  });

  const twoMaterial = new THREE.MeshPhysicalMaterial({
    map: two,
    bumpMap: texture,
    bumpScale: 1,
    roughness: 1,
    metalness: 0,
    // side: THREE.BackSide,
  });

  // Create the Sphere Geometry (a simple sphere)
  const radius = 50; // Size of the ball
  const widthSegments = 64; // Number of horizontal segments
  const heightSegments = 64; // Number of vertical segments
  const sphereGeometry = new THREE.SphereGeometry(
    radius,
    widthSegments,
    heightSegments
  );

  // Scale the sphere to elongate it into a rugby ball shape
  sphereGeometry.scale(1, 1.8, 1);

  // Clear any pre-existing groups
  sphereGeometry.clearGroups();

  if (sphereGeometry.index && sphereGeometry.index.count) {
    console.log("sphereGeometry.index.count: ", sphereGeometry.index.count);
    // Split the sphere into two hemispheres
    const middle = Math.floor(sphereGeometry.index.count / 2);

    // Add group for the top hemisphere (one)
    for (let i = 0; i < middle; i++) {
      sphereGeometry.addGroup(i * 3, 3, 0); // Apply one material to the first half
    }

    // Add group for the bottom hemisphere (two)
    for (let i = middle; i < sphereGeometry.index.count / 3; i++) {
      sphereGeometry.addGroup(i * 3, 3, 1); // Apply two material to the second half
    }
  }

  // Create the mesh and apply the materials
  const materials = [oneMaterial, twoMaterial]; // Two materials: one and two
  const rugbyBall = new THREE.Mesh(sphereGeometry, materials);

  return <primitive object={rugbyBall} position={[0, 0, 0]} scale={2.5} rotation={[-(Math.PI / 2), 0, 0]} />;
};

const Loader = () => {
  const { progress } = useProgress();
  return <Html center>{Math.round(progress)}% loaded</Html>;
};

// Main Scene Component
const Scene = () => {
  return (
    <Canvas
      camera={{ position: [0, 0, 500], fov: 75 }}
      style={{
        width: "100vw",
        height: "30vh",
        backgroundColor: "red",
      }}
    >
      <Suspense fallback={<Loader />}>
        {/* Lighting */}
        <ambientLight intensity={1} />
        <directionalLight position={[0, 1, 0]} intensity={2} />

        {/* 3D Model */}
        <RugbyBall />

        {/* Controls */}
        <OrbitControls autoRotate autoRotateSpeed={2} enableDamping dampingFactor={0.1} />
      </Suspense>
    </Canvas>
  );
};

export default Scene;

Django Formset Dynamic Add/Remove Not Working for Colors, Sizes, and Images

Problem Statement

I am working on a Django formset where users can dynamically add/remove colors, sizes, and images when adding a product.

The structure of my formset is as follows:

  • A product can have multiple colors.
  • Each color can have multiple sizes.
  • Each color can have multiple images.
  • Users should be able to dynamically add/remove colors, sizes, and images using JavaScript.

Expected Behavior

  1. Clicking "Add Color" should create a new color form with its own size and image sections.
  2. Clicking "Add Size" within a color should add a new size only to that specific color.
  3. Clicking "Add Image" within a color should add a new image only to that specific color.
  4. Clicking "Remove Color" should remove the specific color section.

Current Issue

  • Only the “Remove Color” button works.
  • "Add Color", "Add Size", and "Add Image" buttons are not working.
  • No new elements are being appended to the DOM when clicking the buttons.

Debugging Attempts

✔ Checked Django Formset Management Forms (they exist).
✔ Verified event listeners are attached using console.log().
✔ Ensured cloneNode(true) properly copies elements.
✔ Checked for JavaScript errors in the console (no syntax errors).


Django Forms & Formsets

Forms (forms.py)

from django import forms
from django.forms import inlineformset_factory
from .models import VendorProduct, ProductColor, ProductSize, ProductImage, ColorImage

class ProductForm(forms.ModelForm):
    class Meta:
        model = VendorProduct
        fields = ['title', 'category', 'base_price']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'category': forms.Select(attrs={'class': 'form-control'}),
            'base_price': forms.NumberInput(attrs={'class': 'form-control'}),
        }

class ProductColorForm(forms.ModelForm):
    class Meta:
        model = ProductColor
        fields = ['color_name', 'color_code']
        widgets = {
            'color_name': forms.TextInput(attrs={'class': 'form-control'}),
            'color_code': forms.TextInput(attrs={'class': 'form-control'}),
        }

class ProductSizeForm(forms.ModelForm):
    class Meta:
        model = ProductSize
        fields = ['size_name', 'stock', 'price_increment']
        widgets = {
            'size_name': forms.TextInput(attrs={'class': 'form-control'}),
            'stock': forms.NumberInput(attrs={'class': 'form-control'}),
            'price_increment': forms.NumberInput(attrs={'class': 'form-control'}),
        }

class ProductImageForm(forms.ModelForm):
    class Meta:
        model = ProductImage
        fields = ['image']
        widgets = {
            'image': forms.FileInput(attrs={'class': 'form-control'}),
        }

class ColorImageForm(forms.ModelForm):
    class Meta:
        model = ColorImage
        fields = ['image']
        widgets = {
            'image': forms.FileInput(attrs={'class': 'form-control'}),
        }

# Formsets
ProductColorFormSet = inlineformset_factory(VendorProduct, ProductColor, form=ProductColorForm, extra=1, can_delete=True)
ProductImageFormSet = inlineformset_factory(VendorProduct, ProductImage, form=ProductImageForm, extra=1, can_delete=True)
ProductSizeFormSet = inlineformset_factory(ProductColor, ProductSize, form=ProductSizeForm, extra=1, can_delete=True)
ColorImageFormSet = inlineformset_factory(ProductColor, ColorImage, form=ColorImageForm, extra=1, can_delete=True)

HTML Template (add_product.html)

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}

    <div id="colorContainer">
        {% for color_form in color_formset %}
            <div class="color-item">
                {{ color_form.color_name.label_tag }}
                {{ color_form.color_name }}

                {{ color_form.color_code.label_tag }}
                {{ color_form.color_code }}

                <!-- Image Uploads -->
                <label>Color Images</label>
                {{ color_image_formset.management_form }}
                {% for image_form in color_image_formset %}
                    <div class="image-item">
                        {{ image_form.image }}
                    </div>
                {% endfor %}
                <button type="button" class="add-image-btn">Add Image</button>

                <!-- Size Section -->
                <div class="sizeContainer">
                    <h4>Sizes</h4>
                    {{ size_formset.management_form }}
                    {% for size_form in size_formset %}
                        <div class="size-item">
                            {{ size_form.size_name.label_tag }}
                            {{ size_form.size_name }}

                            {{ size_form.stock.label_tag }}
                            {{ size_form.stock }}

                            {{ size_form.price_increment.label_tag }}
                            {{ size_form.price_increment }}
                        </div>
                    {% endfor %}
                </div>
                
                <button type="button" class="add-size-btn">Add Size</button>
                <button type="button" class="remove-btn">Remove Color</button>
            </div>
        {% endfor %}
    </div>

    <button type="button" id="addColorButton">Add Color</button>
    <button type="submit">Save</button>
</form>

JavaScript (dynamic.js)

    document.addEventListener("DOMContentLoaded", function () {
        // Initialize indexes
        let colorIndex = parseInt(document.querySelector('[name="colors-TOTAL_FORMS"]')?.value) || 0;
        let imageIndex = parseInt(document.querySelector('[name="images-TOTAL_FORMS"]')?.value) || 0;

        function addColor() {
            let colorContainer = document.getElementById("colorContainer");
            let totalForms = document.querySelector('[name="colors-TOTAL_FORMS"]');

            if (!totalForms) {
                console.error("Management form for colors-TOTAL_FORMS not found!");
                return;
            }

            let newColor = document.querySelector(".color-item").cloneNode(true);
            newColor.querySelectorAll("input, select").forEach(input => {
                if (input.name) {
                    input.name = input.name.replace(/colors-d+/g, `colors-${colorIndex}`);
                    input.removeAttribute("id"); // Remove duplicate IDs
                    input.value = ""; // Clear input values
                }
            });

            // Attach event listeners to the new color block
            newColor.querySelector(".remove-btn").addEventListener("click", function () {
                removeColor(this);
            });

            newColor.querySelector(".add-size-btn").addEventListener("click", function () {
                addSize(this);
            });

            colorContainer.appendChild(newColor);
            totalForms.value = colorIndex + 1; // Update Django formset tracker
            colorIndex++;
        }

        function addSize(button) {
            let sizeContainer = button.closest(".color-item").querySelector(".sizeContainer");
            let sizeIndex = sizeContainer.querySelectorAll(".size-item").length;

            let newSize = sizeContainer.querySelector(".size-item").cloneNode(true);
            newSize.querySelectorAll("input, select").forEach(input => {
                if (input.name) {
                    input.name = input.name.replace(/sizes-d+/g, `sizes-${sizeIndex}`);
                    input.removeAttribute("id");
                    input.value = ""; // Clear input values
                }
            });

            sizeContainer.appendChild(newSize);
        }

        function removeColor(button) {
            let colorItem = button.closest(".color-item");
            colorItem.remove();

            // Update colors-TOTAL_FORMS count
            colorIndex--;
            document.querySelector('[name="colors-TOTAL_FORMS"]').value = colorIndex;
        }

        function addImage() {
            let imageContainer = document.getElementById("imageContainer");
            let totalForms = document.querySelector('[name="images-TOTAL_FORMS"]');

            if (!totalForms) {
                console.error("Management form for images-TOTAL_FORMS not found!");
                return;
            }

            let newImage = document.querySelector(".image-item").cloneNode(true);
            newImage.querySelectorAll("input").forEach(input => {
                if (input.name) {
                    input.name = input.name.replace(/images-d+/g, `images-${imageIndex}`);
                    input.removeAttribute("id");
                    input.value = ""; // Clear input values
                }
            });

            imageContainer.appendChild(newImage);
            totalForms.value = imageIndex + 1; // Update Django formset tracker
            imageIndex++;
        }

        // Attach event listeners dynamically
        document.getElementById("addColorButton")?.addEventListener("click", addColor);
        document.getElementById("addImageButton")?.addEventListener("click", addImage);

        // Attach existing remove/add-size event listeners for initial elements
        document.querySelectorAll(".remove-btn").forEach(button => {
            button.addEventListener("click", function () {
                removeColor(this);
            });
        });

        document.querySelectorAll(".add-size-btn").forEach(button => {
            button.addEventListener("click", function () {
                addSize(this);
            });
        });
    });

Summary of Issues

  • Event listeners weren’t attached properly.
  • Formset names were not being updated dynamically.
  • JavaScript wasn’t using event delegation properly.
  • The script needed to handle both static and dynamically added elements.

Unhandled SoftException java.lang.RuntimeException: React Native Instance has already disappeared: requested by Timing on APK React Native

I’m having a error on my apk build of my react native expo application, the error just happens on the apk, I can’t reply on the development build. The error just happens specifically 15 minutes after I call a action, a function called createEvento on a generic componet for all Events, and close the app and then try to run the action again after 15 minutes, and then the app has this strange error, stills loading in loop.

I could catch the error using the LogCat of Android Studio with the apj running on my apk
These two errors

 E  Unhandled SoftException
                                                                                                    java.lang.RuntimeException: React Native Instance has already disappeared: requested by Timing
                                                                                                        at com.facebook.react.bridge.BaseJavaModule.getReactApplicationContextIfActiveOrWarn(BaseJavaModule.java:125)
                                                                                                        at com.facebook.react.modules.core.TimingModule.access$000(TimingModule.java:22)
                                                                                                        at com.facebook.react.modules.core.TimingModule$BridgeTimerExecutor.callTimers(TimingModule.java:28)
                                                                                                        at com.facebook.react.modules.core.JavaTimerManager.createAndMaybeCallTimer(JavaTimerManager.java:345)
                                                                                                        at com.facebook.react.modules.core.TimingModule.createTimer(TimingModule.java:84)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
                                                                                                        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:146)
                                                                                                        at com.facebook.jni.NativeRunnable.run(Native Method)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:938)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
                                                                                                        at android.os.Looper.loop(Looper.java:246)
                                                                                                        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:233)

Second error

E Unhandled SoftException
com.facebook.react.bridge.ReactNoCrashSoftException: connectAnimatedNodeToView: Animated node could not be connected to UIManager – uiManager disappeared for tag: 797
at com.facebook.react.animated.NativeAnimatedNodesManager.connectAnimatedNodeToView(NativeAnimatedNodesManager.java:438)
at com.facebook.react.animated.NativeAnimatedModule$18.execute(NativeAnimatedModule.java:838)
at com.facebook.react.animated.NativeAnimatedModule$ConcurrentOperationQueue.executeBatch(NativeAnimatedModule.java:171)
at com.facebook.react.animated.NativeAnimatedModule$3.execute(NativeAnimatedModule.java:365)
at com.facebook.react.uimanager.UIViewOperationQueue$UIBlockOperation.execute(UIViewOperationQueue.java:557)
at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:910)
at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:1023)
at com.facebook.react.uimanager.UIViewOperationQueue.-$$Nest$mflushPendingBatches(Unknown Source:0)
at com.facebook.react.uimanager.UIViewOperationQueue$2.runGuarded(UIViewOperationQueue.java:979)
at com.facebook.react.bridge.GuardedRunnable.run(GuardedRunnable.java:29)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8653)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

import React, { useEffect, useState } from 'react';
import { View, Text, TouchableOpacity, TextInput, Alert, AppState, AppStateStatus, AlertButton } from 'react-native';
import * as SecureStore from 'expo-secure-store';
import BackgroundCustomColor from '@/components/Jornada/BackgroundCustomColor';
import { MaterialCommunityIcons, Octicons } from '@expo/vector-icons';
import { ScrollView } from 'react-native-gesture-handler';
import { ConfirmationJourney } from '@/components/Jornada/ConfirmationJourneyBackground';
import { Timer } from '@/components/Jornada/Timer';
import EventoService from '@/services/api/eventosService';
import QRCodeReader from '@/components/QRCodeReader';
import { verificarLiberacaoQRCode } from '@/utils/verifyParametros';
import UsuarioService from '@/services/api/usuarioService';
import Loading from '@/components/Loading';
import AlertService from '@/services/api/alertService';
import { useNavigation } from '@react-navigation/native';
import { NavigationProp } from '@/types/navigation';
import { useEventosDatabase } from '@/database/useEventosDatabase';
import deactivateBackButton from '@/utils/deactivateBackButton';
import DropDownPicker from 'react-native-dropdown-picker';
import { LISTA_VEICULOS_KEY } from '@/constants/consts';
import { IVeiculo } from '@/types/Veiculo';
import { useAuth } from '@/services/auth/AuthContext';

interface EventProps {
    title: string;
    color: string;
    startEvent: string;
    endEvent: string;
    icon: React.ReactNode;
    confirmationIcon: React.ReactNode;
    isRefeicao?: boolean;
    isDirecao?: boolean;
    isAbastecimento?: boolean;
}

export default function Event({ title, color, startEvent, endEvent, icon, confirmationIcon, isRefeicao, isDirecao, isAbastecimento }: EventProps) {
    const navigation = useNavigation<NavigationProp>();
    const { authState } = useAuth();
    const { createEvento, checkIsUltimoEvento, sendDirecaoData, sendAbastecimentoData } = EventoService();
    const { checkTempoMinRefeicao, checkTempoMaxRefeicao, checkDirecaoTempoMax, checkEncerramentoTurno, checkLimiteEncerramentoTurno } = AlertService();
    const [time, setTime] = useState<number>(0);
    const [startTimer, setStartTimer] = useState<boolean>(false);
    const [confirmationBox, setConfirmationBox] = useState(false);

    const { confirmarLeituraQRCode } = UsuarioService();
    const [QRCodeScanned, setQRCodeScanned] = useState<string | null>();
    const [openScanner, setOpenScanner] = useState<boolean>(false);
    const [loading, setLoading] = useState<boolean>(false);

    const [instanteEvento, setInstanteEvento] = useState<number | null>(null);

    // State para Direcao
    const [dataEvento, setDataEvento] = useState<number>();
    const [dataFimEvento, setDataFimEvento] = useState<number>();
    const [hodometroValue, setHodometroValue] = useState<string>();
    const [hodometroInicial, setHodometroInicial] = useState<string>();
    const [hodometroFinal, setHodometroFinal] = useState<string>();
    const [openFirstDropdown, setOpenFirstDropdown] = useState(false);
    const [itemsFirstDropdown, setItemsFirstDropdown] = useState([
        { label: 'Carregando', value: 1 },
        { label: 'Vazio', value: 2 }
    ]);
    const [valueFirstDropdown, setValueFirstDropdown] = useState(itemsFirstDropdown[0].value);

    const [openSecondDropdown, setOpenSecondDropdown] = useState(false);
    const [itemsSecondDropdown, setItemsSecondDropdown] = useState<{ label: string, value: string | number, hodometro: string | number }[]>([]);
    const [valueSecondDropdown, setValueSecondDropdown] = useState<string>();

    // States para Abastecimento
    const [litrosValue, setLitrosValue] = useState<number | null>(null);
    const [valorPorLitroValue, setValorPorLitroValue] = useState<number | null>(null);
    const [valorTotalValue, setValorTotalValue] = useState<number | null>(null);
    const [openDropdown, setOpenDropdown] = useState(false);
    const [itemsDropdown, setItemsDropdown] = useState([
        { label: 'Alcool', value: 'AL' },
        { label: 'Gasolina', value: 'GA' },
        { label: 'Diesel', value: 'DI' }
    ]);
    const [valueDropdown, setValueDropdown] = useState(itemsDropdown[0].value);

    useEffect(() => {
        deactivateBackButton(startTimer);

        checkIsUltimoEvento(startEvent).then((isLastEvento) => {
            if (isLastEvento?.isUltimoEvento) {
                setStartTimer(true);
                setInstanteEvento(isLastEvento.instanteEvento);
            }
        });

        SecureStore.getItemAsync(LISTA_VEICULOS_KEY).then((result) => {
            const veiculosData = JSON.parse(result!);

            setHodometroValue(veiculosData[0].ultimoHodometro.toString() + ".00");

            if (veiculosData) {
                setItemsSecondDropdown(veiculosData?.map((item: IVeiculo) => {
                    return { label: item.placa, value: item.placa, hodometro: item.ultimoHodometro?.toString() };
                }));

                setValueSecondDropdown(veiculosData[0]?.placa);
            }
        }).catch((error) => console.log("Erro ao buscar lista de veiculos", error));
    }, [startTimer]);

    const handleAppStateChange = (nextAppState: AppStateStatus) => {
        if (nextAppState === 'active') {
            console.log('App has come to the foreground!');
            // Reinitialize or refresh any necessary data here
        }
    };

    useEffect(() => {
        const subscription = AppState.addEventListener('change', handleAppStateChange);
        return () => {
            subscription.remove();
        };
    }, []);

    const handleConfirmJourney = async () => {
        try {
            if (!startTimer) {
                setLoading(true);

                setStartTimer(true);
                const res = await createEvento(startEvent);
                setDataEvento(res);

                setInstanteEvento(res);

                if (isDirecao) {
                    setHodometroInicial(hodometroValue);
                    await checkDirecaoTempoMax();
                }

                await checkTempoMaxRefeicao();
                setLoading(false);
            } else if (startTimer) {
                setLoading(true);

                const res = await createEvento(endEvent);

                setStartTimer(false);
                if (isDirecao) {
                    setDataFimEvento(res);
                    setHodometroFinal(hodometroValue);
                }

                // Enviar dados de direcao
                if (isDirecao && valueFirstDropdown && dataEvento && (res || dataFimEvento) && hodometroValue && valueSecondDropdown) {
                    const data = {
                        tipo: valueFirstDropdown,
                        dataEvento: dataEvento,
                        dataFimEvento: dataFimEvento ?? res,
                        hodometroInicial: Number(hodometroInicial),
                        hodometroFinal: Number(hodometroFinal) ?? Number(hodometroValue),
                        placa: valueSecondDropdown,
                        idVeiculo: authState?.user?.listaDeVeiculos.find((item) => item.placa === valueSecondDropdown)?.id!
                    };
                    await sendDirecaoData(data);
                }

                // Enviar dados de abastecimento
                if (isAbastecimento && litrosValue && valorPorLitroValue && valorTotalValue && valueDropdown) {
                    const data = {
                        quantidadeAbastecida: litrosValue,
                        valorDia: valorPorLitroValue,
                        totalAbastecido: valorTotalValue,
                        tipoCombustivel: valueDropdown
                    };
                    await sendAbastecimentoData(data);
                }

                checkEncerramentoTurno();
                checkLimiteEncerramentoTurno();
                setInstanteEvento(null);

                setLoading(false);
                deactivateBackButton();
                navigation.navigate("Jornada");
            }
        } catch (error) {
            console.log("Erro ao confirmar jornada", error);
            setLoading(false);
        }
        setConfirmationBox(false);
    };

    const handleQRCodeConfirmation = async () => {
        if (await verificarLiberacaoQRCode(title)) {
            if (QRCodeScanned) {
                confirmarLeituraQRCode(QRCodeScanned).then((result) => {
                    if (result?.data.codigoRetorno === 1) {
                        setQRCodeScanned(null);

                        setLoading(false);
                        handleConfirmJourney();
                    } else if (result?.data.codigoRetorno === -1) {
                        Alert.alert(result.data.mensagem + " tente novamente!", undefined, [
                            {
                                text: 'OK', onPress: () => {
                                    setOpenScanner(true);
                                }
                            } as AlertButton,
                        ]);
                        setLoading(false);
                        setQRCodeScanned(null);
                        return;
                    }
                }).catch((error) => {
                    console.log("ERROR", error);
                    alert("Ocorreu um erro. Tente novamente!");
                    setQRCodeScanned(null);
                    setOpenScanner(true);
                    return;
                });
            } else {
                setOpenScanner(true);
            }
        } else {
            handleConfirmJourney();
        }
    };

    if (openScanner) return (
        <QRCodeReader
            setCodeScanned={setQRCodeScanned}
            qrCodeValue={QRCodeScanned}
            onCodeScanned={handleQRCodeConfirmation}
            setLoading={setLoading}
            setOpenScanner={setOpenScanner}
        />
    );

    return (
        <View className='flex-1 w-full'>
            {!confirmationBox ? (<BackgroundCustomColor color={color}>
                <ScrollView contentContainerStyle={{ flex: 1 }}>
                    <View className="flex-1 items-center justify-between py-3">

                        <View className='items-center'>
                            <Text className='text-white text-3xl font-bold uppercase'>{title}</Text>

                            {isDirecao && (
                                <View className='mt-3'>
                                    <DropDownPicker
                                        listMode='SCROLLVIEW'
                                        style={{ backgroundColor: color, borderColor: "transparent", paddingLeft: 0, zIndex: 1 }}
                                        dropDownContainerStyle={{ borderColor: "transparent", width: '70%', borderRadius: 0, zIndex: 20 }}
                                        textStyle={{ color: "black", fontSize: 20, textTransform: "uppercase" }}
                                        labelStyle={{ color: "white" }}
                                        badgeTextStyle={{ color: "black" }}
                                        ArrowUpIconComponent={() => (<Octicons name="triangle-up" size={24} color="black" />)}
                                        ArrowDownIconComponent={() => (<Octicons name="triangle-down" size={24} color="black" />)}
                                        placeholder="Seleciono o tipo"
                                        ListEmptyComponent={() => <Text>Nenhum item</Text>}
                                        open={openFirstDropdown}
                                        value={valueFirstDropdown}
                                        items={itemsFirstDropdown}
                                        setOpen={() => {
                                            setOpenFirstDropdown(!openFirstDropdown);
                                            setOpenSecondDropdown(false);
                                        }}
                                        setValue={setValueFirstDropdown}
                                        setItems={setItemsFirstDropdown}
                                    />
                                    {itemsSecondDropdown.length > 0 && (
                                        <DropDownPicker
                                            listMode='SCROLLVIEW'
                                            style={{ backgroundColor: color, borderColor: "transparent", paddingLeft: 0, zIndex: 1 }}
                                            dropDownContainerStyle={{ borderColor: "transparent", width: '70%', borderRadius: 0, zIndex: 10 }}
                                            textStyle={{ color: "black", fontSize: 20, textTransform: "uppercase" }}
                                            labelStyle={{ color: "white" }}
                                            badgeTextStyle={{ color: "black" }}
                                            ListEmptyComponent={() => <Text className='uppercase text-lg font-bold'>Nenhum item</Text>}
                                            ArrowUpIconComponent={() => (<Octicons name="triangle-up" size={24} color="black" />)}
                                            ArrowDownIconComponent={() => (<Octicons name="triangle-down" size={24} color="black" />)}
                                            placeholder="PLACA"
                                            placeholderStyle={{ color: "white" }}
                                            open={openSecondDropdown}
                                            value={valueSecondDropdown ?? null}
                                            items={itemsSecondDropdown}
                                            setOpen={() => {
                                                setOpenSecondDropdown(!openSecondDropdown);
                                                setOpenFirstDropdown(false);
                                            }}
                                            // @ts-ignore
                                            onSelectItem={(item) => setHodometroValue(item.hodometro + ".00")}
                                            setValue={setValueSecondDropdown}
                                            setItems={setItemsSecondDropdown}
                                        />
                                    )}
                                    <TextInput
                                        value={hodometroValue}
                                        onChangeText={(value) => setHodometroValue(value)}
                                        className='min-w-[90%] p-1 border-b-[1px] border-b-[#745419] text-2xl text-white uppercase'
                                        placeholderTextColor={"white"}
                                        keyboardType='number-pad'
                                        placeholder='Hodômetro' />
                                </View>
                            )}

                            {isAbastecimento && (
                                <View className='mt-3 gap-5'>
                                    <DropDownPicker
                                        listMode='SCROLLVIEW'
                                        style={{ backgroundColor: color, borderColor: "transparent", paddingLeft: 0, zIndex: 1 }}
                                        dropDownContainerStyle={{ borderColor: "transparent", width: '70%', borderRadius: 0, zIndex: 10 }}
                                        textStyle={{ color: "black", fontSize: 20, textTransform: "uppercase" }}
                                        labelStyle={{ color: "white" }}
                                        badgeTextStyle={{ color: "black" }}
                                        ArrowUpIconComponent={() => (<Octicons name="triangle-up" size={24} color="black" />)}
                                        ArrowDownIconComponent={() => (<Octicons name="triangle-down" size={24} color="black" />)}
                                        placeholder=""
                                        open={openDropdown}
                                        value={valueDropdown}
                                        items={itemsDropdown}
                                        setOpen={() => {
                                            setOpenDropdown(!openDropdown);
                                        }}
                                        setValue={setValueDropdown}
                                        setItems={setItemsDropdown}
                                    />

                                    <TextInput
                                        value={litrosValue?.toString()}
                                        onChangeText={(value) => setLitrosValue(Number(value))}
                                        className='min-w-[90%] p-1 border-b-[1px] border-b-[#431242] focus:border-b-[#008577] text-2xl text-white uppercase'
                                        placeholderTextColor={"white"}
                                        keyboardType='numeric'
                                        placeholder='Litros Combustível' />

                                    <TextInput
                                        value={valorPorLitroValue?.toString()}
                                        onChangeText={(value) => setValorPorLitroValue(Number(value))}
                                        className='min-w-[90%] p-1 border-b-[1px] border-b-[#431242] focus:border-b-[#008577] text-2xl text-white uppercase'
                                        placeholderTextColor={"white"}
                                        keyboardType='numeric'
                                        placeholder='Valor por Litro' />

                                    <TextInput
                                        value={valorTotalValue?.toString()}
                                        onChangeText={(value) => setValorTotalValue(Number(value))}
                                        className='min-w-[90%] p-1 border-b-[1px] border-b-[#431242] focus:border-b-[#008577] text-2xl text-white uppercase'
                                        placeholderTextColor={"white"}
                                        keyboardType='numeric'
                                        placeholder='Valor Total' />
                                </View>
                            )}
                        </View>

                        <View className='items-center gap-4'>
                            {icon}
                            <View className='flex-row items-center gap-4'>
                                <Timer handleSetTime={setTime} startTimer={startTimer} actualTime={time} instanteEvento={instanteEvento} />
                            </View>
                            {startTimer ? (
                                <TouchableOpacity style={{ marginBottom: 15 }} onPress={() => {
                                    setConfirmationBox(true);
                                    isRefeicao && checkTempoMinRefeicao();
                                }}>
                                    <View className='bg-red-soft px-12 py-0.5 text-white font-bold text-center self-center rounded-lg flex-col'>
                                        <Text className='text-lg text-white font-bold text-center uppercase'>ENCERRAR</Text>
                                        <Text className='text-xs text-white font-bold text-center uppercase'> {title}</Text>
                                    </View>
                                </TouchableOpacity>
                            ) : (
                                <TouchableOpacity style={{ marginBottom: 15 }} onPress={() => setConfirmationBox(true)}>
                                    <View className='bg-green-lightdark px-12 py-0.5 text-white font-bold text-center self-center rounded-lg flex-col'>
                                        <Text className='text-lg text-white font-bold text-center uppercase'>INICIAR</Text>
                                        <Text className='text-xs text-white font-bold text-center uppercase'> {title}</Text>
                                    </View>
                                </TouchableOpacity>
                            )}
                        </View>
                    </View>
                </ScrollView>
            </BackgroundCustomColor>) : (
                <ConfirmationJourney onConfirm={() => handleQRCodeConfirmation()} onCancel={() => setConfirmationBox(false)}>
                    <ConfirmationJourney.Text>Deseja {time > 0 ? "ENCERRAR" : "INICIAR"} {title}?</ConfirmationJourney.Text>
                    <ConfirmationJourney.Icon>{confirmationIcon}</ConfirmationJourney.Icon>
                </ConfirmationJourney>
            )}
            {loading && <Loading />}
        </View>
    );
}

I’m burning out my head to solve this very strange error, holpe someone can help me

Bad rate on pancakeswap

The rate of the transaction is always smaller than expected.

For example, I should be able to buy 7-8 tokens, but I only get 5-6. The same happens when I buy with WBNB — the rate is still not as good as it should be.

What am I doing wrong? I am doing the approval transaction first, followed by the swap.

Do you have any examples or suggestions on how I can do this correctly?

Please help!

import { ethers } from "ethers";

const privateKey = "...";

const provider = new ethers.JsonRpcProvider("https://bsc-dataseed.binance.org/");
const wallet = new ethers.Wallet(privateKey, provider);

const sellContract = "0x55d398326f99059ff775485246999027b3197955";
const buyContract = "0x9840652DC04fb9db2C43853633f0F62BE6f00f98";
const routerAddress = "0x10ED43C718714eb63d5aA57B78B54704E256024E";

const usdtABI = [
    "function balanceOf(address owner) view returns (uint256)",
    "function approve(address spender, uint256 amount) public returns (bool)"
];

const routerABI = [
    "function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)",
    "function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)"
];

const sellContractInstance = new ethers.Contract(sellContract, usdtABI, wallet);
const routerContract = new ethers.Contract(routerAddress, routerABI, wallet);

const usdtAmount = ethers.parseUnits("1.00", 18);
const toAddress = wallet.address;

async function buyTokens() {
    const normalizedSellContract = ethers.getAddress(sellContract);
    const normalizedBuyAddress = ethers.getAddress(buyContract);
    const path = [normalizedSellContract, normalizedBuyAddress];
    const deadline = Math.floor(Date.now() / 1000) + 600;

    try {
        const usdtBalance = await sellContractInstance.balanceOf(wallet.address);
        console.log('USDT Balance:', ethers.formatUnits(usdtBalance, 18));

        const amountsOut = await routerContract.getAmountsOut(usdtAmount, path);
        const expectedTokens = BigInt(amountsOut[1]);
        console.log(`Ожидаемое количество токенов: ${ethers.formatUnits(expectedTokens, 18)}`);

        const slippageTolerance = 10;
        const amountOutMin = (expectedTokens * BigInt(100 - slippageTolerance)) / BigInt(100);
        console.log(`Минимальное количество токенов с учетом ${slippageTolerance}% slippage: ${ethers.formatUnits(amountOutMin, 18)}`);

        const approvalTx = await sellContractInstance.approve(routerAddress, usdtAmount, {
            gasLimit: 500000,
            gasPrice: ethers.parseUnits("1", "gwei")
        });
        console.log("Approval successful");

        const tx = await routerContract.swapExactTokensForTokens(
            usdtAmount,
            amountOutMin.toString(),
            path,
            toAddress,
            deadline,
            {
                gasLimit: 500000,
                gasPrice: ethers.parseUnits("1", "gwei")
            }
        );
        console.log("Transaction sent, awaiting confirmation...");
        console.log("Transaction confirmed!");
    } catch (error) {
        console.error("Error in buying tokens:", error);
    }
}

buyTokens();

How to prevent Angular trimming input value

I have the following code. The problem is it doesn’t flag invalid when there is leading or trailing spaces. Then I print out the value and found that the surrounding spaces are automatically trimmed so it cannot be detected by the pattern validator. I can only find solution for AngularJS, but not Angular, is there any equivalent in Angular?

<input matInput #email="ngModel" name="email" [(ngModel)]="email" type="email" (ngModelChange)="onEmailChanged($event);"
[pattern]="emailRegex">
readonly emailregex = /^([-!#-'*+/-9=?A-Z^-~]+(.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ t]|(\[t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])$/;
email = "";

onEmailChanged(event:Event){
    console.log("onEmailChanged", email);
}

Display restaurants grouped by city in MEN stack

I am new to development and currently working on a MEN stack project.

My project is currently setup with a User schema that has an embedded restaurantSchema.
The restaurantSchema contains a city section and I want to display restaurants on my index.ejs view grouped by the city they are in.

const restaurantSchema = new mongoose.Schema({
  city: {
    type: String,
    required: true,
    enum: ["Houston", "Dallas", "Austin", "San Antonio"],
  },
  name: {
    type: String,
    required: true,
});

Specifically, I want to display all restaurants under their respective city names. However, I’m unsure of how to implement this in my view.

I currently have the view setup as showing all the restaurants as a single list.

<body>
    <%- include('../partials/_navbar.ejs') %>
    <ul>
      <% restaurants.forEach(restaurant => { %>
        <li>
          <a href="/users/<%=user._id%>/restaurants/<%=restaurant._id%>">
            <%= restaurant.name %>
          </a>
        </li>
      <% }) %>
    </ul>
    <br>
    <a href="/users/<%=user._id%>/restaurants/new">Add a New Restaurant</a>
  </body>

How to set Youtrack issues state on Pull Requests update via JS workflows

I need to put a Youtrack issue into a Done state when the corresponding Pull Request is merged. I am using Javascript workflows and listening for issue changes.

Expected and Actual

I expected to be able to know which Pull Request was added, its current state (OPEN, MERGED, DECLINED) and its state before the current transaction.

But I see that every item in ctx.issue.pullRequests has isNew=false no matter what I do. Contrary to what it says in documentation

I tried

  • Get ctx.issue.oldValue('pullRequests'), but it returns the same as ctx.issue.pullRequests.
  • Calling isChanged() for each pullRequest item in the list, as well as for the pullRequest.state field. But it always false.

My temporary solution

So the only solution I have is to get the last fetched PR when updating the list of issue PRs and check if its state is MERGED.

Here is my code:

const entities = require('@jetbrains/youtrack-scripting-api/entities');

exports.rule = entities.Issue.onChange({
  title: 'Move task to "Done" when PR merged',
  guard: (ctx) => {
    if (ctx.issue.isChanged('pullRequests')) {

      const pullRequests = [];
      ctx.issue.pullRequests.forEach((pullRequest) => pullRequests.push(pullRequest));
      
      pullRequests.sort((a, b) => b.fetched - a.fetched);

      return pullRequests[pullRequests.length - 1].state.name == 'MERGED';
    } else {
      return false;
    }
  },
  action: (ctx) => {
    if (ctx.issue.fields.State && !ctx.issue.fields.State.is(ctx.State.Done)) {
      ctx.issue.fields.State = ctx.State.Done;
    }
  },
  requirements: {
    State: {
      type: entities.State.fieldType,
      name: 'State',
      Done: {}
    }
  }
});

I also can’t figure out what the ctx.issue.pullRequests object represents. I can only call .forEach() on it.

MediaSource not playing video chunk: Source buffer has been removed from parent media source

I am fetching 1MB chunks of a short form mp4 video from my express server:

_app.get('/video/:id', async (req, res) => {
        if (!res.locals.authed && !process.env._DEBUG) return rpjson(res, ServerResponse.authFail);
        var id, byteDifference, byteStart, byteEnd = 0;
        

        try {
            id = parseInt(req.params.id);
            byteStart = req.query.byteStart ? parseInt(req.query.byteStart) : 0;
            if (req.query.byteEnd) byteEnd = parseInt(req.query.byteEnd);

            if(byteEnd == 0)
                byteEnd = byteStart + VIDEO_CHUNK_SIZE - 1;

            byteDifference = byteEnd - byteStart + 1;
                
            if (id === undefined) return rpjson(res, ServerResponse.invalidPayload);
        } catch (err) {
            return rpjson(res, ServerResponse.invalidPayload)
        }

        const video = await dbGetVideoData(id, byteStart + 1, byteDifference);
        if (video === null) return rpjson(res, ServerResponse.invalidPayload);
        if (video.chunk === null) return rpjson(res, ServerResponse.invalidPayload);

        const contentLength = Math.min(byteDifference, video.data_length - byteStart);

        var statusCode = 206;
        var headers = {
            'Content-Range': `bytes ${byteStart}-${byteEnd}/${video.data_length}`,
            'Accept-Ranges': 'bytes',
            'Content-Length': `${contentLength}`,
            'Content-Type': 'video/mp4',
            'Access-Control-Expose-Headers': 'Content-Range, Content-Length'
        };



        if (byteEnd > video.data_length) {
            byteEnd = video.data_length;
            statusCode = 200;
            delete headers['Content-Range'];
        }
        res.writeHead(statusCode, headers);
        res.end(video.chunk);
    });

I query this endpoint with a react component ChunkedVideoPlayer:



export default function ChunkedVideoPlayer({ videoID, url = null,
    chunkSizeb = 1000000,
    codecStr = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
    ...videoProps }) {

    if (url == null)
    {
        url = process.env.CONTENT_SERVER_URL + "/video";
    }
    const currentVideo = {
        rawUrl: null,
        size: null,
        nextChunkIndex: 0,
        nextChunkStart: 0,
        nextChunkEnd: chunkSizeb
    };
    const [mediaSource, setMediaSource] = useState();

    const prepareChunkUrl = () => {
        if (!currentVideo.rawUrl) 
            currentVideo.rawUrl = url + videoID;
        return `${currentVideo.rawUrl}?byteStart=${currentVideo.nextChunkStart}&byteEnd=${currentVideo.nextChunkEnd}`;
    }
    function fetchNextChunk(srcBuffer) {
        const nurl = prepareChunkUrl();
        console.log(nurl)
        fetch(nurl)
            .then((res) => {
                if (!res.ok || (res.status !== 200 && res.status != 206)) {
                    setError("Something Unexpected happened.");

                    // try again
                    return setTimeout(fetchNextChunk(srcBuffer), 1000);
                }
                if (res.headers.has('content-length')) currentVideo.size = parseInt(res.headers.get('content-length'));
                res.arrayBuffer().then((data) => 
                    {
                        srcBuffer.appendBuffer(data)
                    });
            });
    }
    function getVideo() {
        const video = document.querySelector('video');
        if (!video || !('MediaSource' in window)) return;

        const ms = new MediaSource();
        setMediaSource(ms);

        video.src = URL.createObjectURL(ms);
        currentVideo.rawUrl = `${url}/${videoID}`;

        ms.addEventListener('sourceopen', () => {
            const srcbuffer = ms.addSourceBuffer(codecStr);
            
            srcbuffer.addEventListener('updateend', () => {
                console.log('ended');
                if (currentVideo.nextChunkStart + chunkSizeb < currentVideo.size)
                {
                    currentVideo.nextChunkStart += chunkSizeb;
                    currentVideo.nextChunkEnd += chunkSizeb;
                
                    fetchNextChunk(srcbuffer);
                }
                else ms.endOfStream();
            });
            fetchNextChunk(srcbuffer);
        })
    }

    useEffect(getVideo, [videoID]);
    if (videoID === undefined || videoID == -1) return <div className="loading"></div>;
    return <video {...videoProps} ></video>;
}

I have printed the bytes received by the endpoint and it has been received successfully. However, the mediaSource buffer is not playing the video, and gives this error to the console:

InvalidStateError: Failed to execute 'appendBuffer' on 'SourceBuffer': This SourceBuffer has been removed from the parent media source.

Ive scoured the docs and other questions similar to this and none seem to fix my issue. I think I am using the MediaSource API correctly? I’d appreciate any help.

DocketWise api query to get the matters that were updated just today

I want to get the matters that passed to the next status in appscript so i was thinking about the next link

https://app.docketwise.com/api/v1/matters?status_changed_since=
2025-02-20
&limit=
200
&offset=
0

To get the maximum request possibles and then doing an offset increment change the page but the part of ?status_changed_since= does not work it continues giving me all the past matters created before the date I put in the link is there a way to do it?

I tried ?updated_since but did not work and i want the array of matters as an [object, object] to work with them

How to execute two different functions depending on screen size, desktop vs. mobile?

I made a simple flip book website and I am now trying to make it more responsive for mobile. When the user is on desktop, the book translates(flips) on the Y axis. When the user is on mobile, I want the book to translate on the x axis like a notepad. I tried setting up an if statement for when the screen size in less than 870 px to translate on the x axis but I got an error and nothing happens.
Line 21-45 is my function for mobile and line 51-57 is my function for desktop.
Can anyone help?

// References to DOM Elements
const prevBtn = document.querySelector("#prev-btn");
const nextBtn = document.querySelector("#next-btn");
const book = document.querySelector("#book");

const paper1 = document.querySelector("#p1");
const paper2 = document.querySelector("#p2");
const paper3 = document.querySelector("#p3");
const paper4 = document.querySelector("#p4");

// Event Listener
prevBtn.addEventListener("click", goPrevPage);
nextBtn.addEventListener("click", goNextPage);

// Business Logic
let currentLocation = 1;
let numOfPapers = 4;
let maxLocation = numOfPapers + 1;

let onMobile;
const resizeEvent = fuction(){
    if(window.innerWidth <= 870){
        onMobile =true;
    }
    else{
        onMobile = flase;
    }
}

resizeEvent();

$(window).on('resize', resizeEvent);

function openBook() {
    book.style.transform = "translateY(50%)";
    prevBtn.style.transform = "translateY(-180px)";
    nextBtn.style.transform = "translateY(180px)";
}

function closeBook(isAtBeginning) {
    if(isAtBeginning) {
        book.style.transform = "translateX(0%)";
    } else {
        book.style.transform = "translateX(100%)";
    }
    
    prevBtn.style.transform = "translateX(0px)";
    nextBtn.style.transform = "translateX(0px)";
}

function openBook() {
    book.style.transform = "translateX(50%)";
    prevBtn.style.transform = "translateX(-180px)";
    nextBtn.style.transform = "translateX(180px)";

}

function closeBook(isAtBeginning) {
    if(isAtBeginning) {
        book.style.transform = "translateX(0%)";
    } else {
        book.style.transform = "translateX(100%)";
    }
    
    prevBtn.style.transform = "translateX(0px)";
    nextBtn.style.transform = "translateX(0px)";
}

function goNextPage() {
    if(currentLocation < maxLocation) {
        switch(currentLocation) {
            case 1:
                openBook();
                paper1.classList.add("flipped");
                paper1.style.zIndex = 1;
                break;
            case 2:
                paper2.classList.add("flipped");
                paper2.style.zIndex = 2;
                break;
            case 3:
                paper3.classList.add("flipped");
                paper3.style.zIndex = 3;
                break; 
            case 4:
                paper4.classList.add("flipped");
                paper4.style.zIndex = 4;
                closeBook(false);
                break;
            default:
                throw new Error("unkown state");
        }
        currentLocation++;
    }
}

function goPrevPage() {
    if(currentLocation > 1) {
        switch(currentLocation) {
            case 2:
                closeBook(true);
                paper1.classList.remove("flipped");
                paper1.style.zIndex = 4;
                break;
            case 3:
                paper2.classList.remove("flipped");
                paper2.style.zIndex = 3;
                break;
            case 4:
                openBook();
                paper3.classList.remove("flipped");
                paper3.style.zIndex = 2;
                break;
            case 5:
                openBook();
                paper4.classList.remove("flipped");
                paper4.style.zIndex = 1;
                break;

            default:
                throw new Error("unkown state");
        }

        currentLocation--;
    }
}

export const setPlaceholderText = () => {
    const input = document.getElementById("")
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: sans-serif;
  background-color: powderblue;
}

/* Book */
.book {
  position: relative;
  width: 550px;
  height: 700px;
  transition: transform 0.5s;
  
}

.paper {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  perspective: 1500px;

}

.front,
.back {
  background-color: white;
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  transform-origin: left;
  transition: transform 0.5s;
}

.front {
  z-index: 1;
  backface-visibility: hidden;
  border-left: 3px solid powderblue;
}

.back {
  z-index: 0;
}

.front-content,
.back-content {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.back-content {
  transform: rotateY(180deg)
}

/* Paper flip effect */
.flipped .front,
.flipped .back {
  transform: rotateY(-180deg);
}

/* Controller Buttons */
button {
  border: none;
  background-color: transparent;
  cursor: pointer;
  margin: 100px;
  transition: transform 0.5s;
}

button:focus {
  outline: none;
}

button:hover i {
  color: #636363;
}

i {
  font-size: 50px;
  color: gray;
}

/* Paper stack order */
#p1 {
  z-index: 4;
}

#p2 {
  z-index: 3;
}

#p3 {
  z-index: 2;
}

#p4 {
  z-index: 1;
}

@media ( max-width: 870px){

  .book {
    position: relative;
  right:10px;
    width: 450px;
    height: 600px;
    transition: transform 0.5s;
    
  }
  button {
    margin: 5px;
  }

  .back-content {
    transform: rotateX(180deg)
  }
  
  /* Paper flip effect */
  .flipped .front,
  .flipped .back {
    transform: rotateX(-180deg);
  }
  
 
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Book</title>
    <link rel="stylesheet" href="style.css">
    <script src="index.js" defer></script>
    <script src="https://kit.fontawesome.com/b0f29e9bfe.js" crossorigin="anonymous"></script>
</head>
<body>
    <!-- Previous Button -->
    <button id="prev-btn">
       <img src="back.png">
    </button>


    <!-- Book -->
    <div id="book" class="book">
        <!-- Paper 1 -->
        <div id="p1" class="paper">
            <div class="front">
                <div id="f1" class="front-content">
                    <h1>Front 1</h1>
                </div>
            </div>
            <div class="back">
                <div id="b1" class="back-content">
                    <h1>Back 1</h1>
                </div>
            </div>
        </div>
        <!-- Paper 2 -->
        <div id="p2" class="paper">
            <div class="front">
                <div id="f2" class="front-content">
                    <h1>Front 2</h1>
                </div>
            </div>
            <div class="back">
                <div id="b2" class="back-content">
                    <h1>Back 2</h1>
                </div>
            </div>
        </div>
        <!-- Paper 3 -->
        <div id="p3" class="paper">
            <div class="front">
                <div id="f3" class="front-content">
                    <h1>Front 3</h1>
                </div>
            </div>
            <div class="back">
                <div id="b3" class="back-content">
                    <h1>Back 3</h1>
                </div>
            </div>
        </div>
<!-- Paper 4 -->
<div id="p4" class="paper">
    <div class="front">
        <div id="f4" class="front-content">
            <h1>Front 4</h1>
        </div>
    </div>
    <div class="back">
        <div id="b4" class="back-content">
            <h1>Back 4</h1>
        </div>
    </div>
</div>


    </div>

    <!-- Next Button -->
    <button id="next-btn">
       <img src="next.png">
    </button>
<script src="index.js"></script>
</body>
</html>