Quantcast
Channel: Ionic Forum - Latest topics
Viewing all 70958 articles
Browse latest View live

Ionic 7 Update and Android Studio

$
0
0

Hi All

I never previously had andriod studio issue related to my Ionic project but after update to 7, i am getting these DebugAndriodTestManifest errors.

When migrating the Ionic Project, is there a correct way to generate the Android project? I mean, as clean re-creation, but still getting my project settings, etc?
t seems that the migration from Ionic 6 to 7 has somehow affected my Andriod Project.

4 posts - 2 participants

Read full topic


Where to place the PrivacyInfo.xcprivacy file

$
0
0

Hello

I am using the ionicframework online tool builder. So I upload to Github a minimal amount of files, basically some config files and all files inside /src.

As I am not using XCode or Visual Studio, I don´t know where should I place PrivacyInfo.xcprivacy file.

I have tried at root and in /ios folder but when I download the xcarchive, I don´t find it inside, so I think that the system is not recognizing it when gets the code from GitHub.

How should I proceed?

Thanks.

2 posts - 2 participants

Read full topic

Signaturepad ionic 7 angular 17.3

$
0
0

Hi there,

I wanted to intigrate Signaturepad in my project. I tried some different versions but nothing is working. Is there a working one? Please help

1 post - 1 participant

Read full topic

Where are gray colors in the theme are defined and how can we override them?

$
0
0

If an Ionic app is built with the default theme, that is, without touching its theming code (scss); and it is being viewed on (say) an Android platform in the default ‘md’, ‘Light’ mode. Then…

The UI will contain the 9 colors (primary, secondary, tertiary, and so on), AND shades of gray applied to some elements and controls.

I understand that I can customize those 9 colors (primary, secondary, tertiary, and so on), by changing the values of the variables in the file varialbles.scss. But I don’t understand from where the gray shades in the UI are being defined, and how I can customize or override those gray colors as per my requirements.

1 post - 1 participant

Read full topic

How can I change my default project when doing an ionic build?

$
0
0

I have my angular.json set to use multiple projects, and my mobile project has a namespace of “app-mobile”.

When I try and build with

ionic build --configuration production

which runs the command

ng.cmd run app:build:production

I get the error: Project “app” does not exist.

How can I change this to run

ng.cmd run app-mobile:build:production

1 post - 1 participant

Read full topic

"Error: "PluginName" plugin is not implemented on ios" after Capacitor 6 update

$
0
0

We just updated our app to Capacitor 6. Everything appeared to have worked fine. The Android app is working fine. We have implemented a few custom plugins. These work fine on Android. The don’t work on iOS, we get this error: Error: "PluginName" plugin is not implemented on ios.

We tried running the troubleshooting steps mentioned here: iOS Troubleshooting Guide | Capacitor Documentation

Plugins that we installed through npm work fine. Only our custom plugins don’t work. We did follow this guide: Updating plugins to 6.0 | Capacitor Documentation as well as checked what other open source plugins changed (there haven’t been any major changes on iOS as far as I can see).

We are using SPM and have used SPM before the Capacitor 6 update. We don’t use SPM capacitor dependencies, only for dependencies we require for native iOS code (so we are using Pods + SPM and do so for several months).

Do you have any idea what we could try to fix this issue?

1 post - 1 participant

Read full topic

Unable to remove Button background on hover

$
0
0

I have an IonButton component with the fill set to “clear” and the class isLink on it.
In my css I’m trying to override the default hover background color, but nothing is working. I’ve tried the following approaches:

Doesn’t work:

.isLink {
  --background-hover: none;
}

Doesn’t work:

.isLink::part(native):hover {
  background: none;
}

Doesn’t work:

.isLink::part(native):hover {
  --background-hover: none;
}

If I set the background to “red” instead of “none” or “transparent”, it works fine like this:

.isLink::part(native):hover {
  background: red;
}

What’s going on here? What’s the correct way to override this style?

1 post - 1 participant

Read full topic

iOS - Tap on status bar doesn't scroll to top

$
0
0

I am using Ionic 8 and Capacitor 6.
My (still PWA but soon to be) app is set up based on ion-tabs with list items in each tab view.
When scrolling any of those lists and tapping on the status bar my expected behaviour would be the list to scroll to the top. However, when tapping the status bar neither in Safari nor installed as PWA (still Webkit) would scroll to the top. Nothing happens at all.

What I have tried:

  • Added statusBar: false option to IonicVue config - unfortunately just like swipeBackEnabled: false none of these have any effect.

  • Added Capacitor StatusBar, Style plugins and added event listener statusTap. This didn’t work either.

I don’t know if the above settings are supposed to work when the vue app is deployed as ios app. Howewer, something seems to prevent tapping of the status bar to be fired.

If you need sample code, I’ll be happy to provide it, however - as I mentioned - it’s pretty much the ion-tabs code sample with list items in each tab view.

I have tried on an iPhone XS, an iPad Pro (Gen. 1) both with iOS 17.4.1 and on Simulator app iPhone 15 Pro Max also on iOS 17.4.1.

Edit: I just tried it on two of the examples from docs and tapping the status bar there wouldn’t do anything as well (opened the iframe urls directly):
https://ionicframework.com/docs/usage/v8/infinite-scroll/basic/demo.html
https://ionicframework.com/docs/usage/v8/header/translucent/demo.html

1 post - 1 participant

Read full topic


Camera capacitor plugin tools:ignore="MissingClass" error

$
0
0

Hy i tryed to use the @capacitor/camera plugin with the description from here:

When running the app in Android studio i get the following error:
The prefix “tools” for attribute “tools:ignore” associated with an element type “service” is not bound.

when i remove the line tools:ignore=“MissingClass” from the AndroidManifest.xml everything works fine.

What is tools:ignore=“MissingClass” normaly used for ?
Is there another proper way to resolve this error ?

Thanks for your ansers

1 post - 1 participant

Read full topic

New Project Error: Downloading and extracting blank starter Error: read ECONNRESET

$
0
0

Hello… I’m Rod. This happend when I try to create a new project with: ionic start myApp in blank

  • Environmentes Information: Ionic 7.2.0 & Ionic CLI : 7.2.0
  • Utility:
  • cordova-res : not installed globally
  • native-run : not installed globally
  • System: NodeJS : v18.13.0 npm : 8.19.3 OS : Windows 10

ERROR MESSAGE!!!:

\ Downloading and extracting blank starter Error: read ECONNRESET
** at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20) {**
** errno: -4077,**
** code: ‘ECONNRESET’,**
** syscall: ‘read’,**
** response: undefined**
}

Hope helps you

SOLUTION: provided by hauthorn
Follow up: I had Killer Network OEM software installed. Disabling all related services fixed the issue.

1 post - 1 participant

Read full topic

Best website to get the latest sports and casino updates

$
0
0

Lion567 News is the one of the best website to get the latest sports and casino updates and headlines. Their commitment drives us to provide you with timely and captivating content to keep you well-informed. Count on Lion567 News for real-time, reliable, and engaging updates from the dynamic worlds of sports and casino gaming, delivering news and insights that truly make a difference.

Visit: https://lion567.news/

1 post - 1 participant

Read full topic

Best online casino website

$
0
0

Lion567 is the best online casino website for real money with a wide variety of games. As India’s largest and most reliable online casino, LION567 is committed to promoting a safe and controlled environment. Their platform encourages players to gamble responsibly and limits deposits to ensure a positive gaming experience. For the best live casino experience, Visit: https://www.lion567.com/en

1 post - 1 participant

Read full topic

Capacitor Javascript Chart.js

$
0
0

Hello,
I need to make as simple as possible multiplatform application (Windows, macOS, iOS, Android) I chose html, css + js. And for Windows and Mac I use electron (everything works here). And for iOS and Android I chose Capacitor. I have converted and launched the project, after some time everything works (HTTP GET and SET), but I have a problem with chart.js charts in Capacitor. I installed the plugin:
npm install chart.js
And added to package.json:
"chart.js":"^4.4.2"
Next in the .js file where I want to use the charts:
<script src="../node_modules/chart.js/dist/chart.umd.js"></script>
And then I already use the plugin.
The problem is that on both android and iOS I only get a blank space rendered. (In Electron everything works).
I would be very grateful for advice.

Thank you and excuse me. I am a newbie

2 posts - 2 participants

Read full topic

Using the Camera.pickImages is crashing on iOS if I choose more than approx 20 images

$
0
0

Using Capacitor 5.7.2 with Camera plugin 5.0.9.

It mostly works great, right up until I choose more than 20-30 photos, depending on the phone. It then crashes my app, I assume because it’s out of memory.

Permissions are fine as it DOES work most of the time and I’ve double checked them. They are all there. It shows the image gallery, allows me to pick the images and click Add to select them.

Here is the relevant code.

const options: GalleryImageOptions = {	
    correctOrientation: true,			
    presentationStyle: "fullscreen"
}

const galleryPhotos: GalleryPhotos = await Camera.pickImages(options);

Any ideas on what I can do here or if I’m doing anything wrong?

1 post - 1 participant

Read full topic

How to configure ionic apk to use https

$
0
0

i build an android application using ionic framework using angular and capacitor, when i call my api with http its work fine and i get data, but when i use https i get canceled status in the debugger, the server work fine with https, i try to call the api with postman and its work fine, so if there is any configuration or plugin to add i would be glad to be informed;

1 post - 1 participant

Read full topic


Missing swiftsupport folder after updating capacitor

$
0
0

Hi all, currently I am on capacitor 5. When summiting to the iOS app store, we receive the error missing swiftsupport folder, the current minimum target of ios version is 13. I have suggested solution this issue can be resolved when we reduce the target version to version 11, however minimum requirement for iOS version for capacitor 5 is version 13. How can we resolve this issue? Can anyone help?
@capacitor/core”: “^5.0.0”
@ionic/cli”: “^6.17.1”

1 post - 1 participant

Read full topic

Vulnerabilty in ionic.js regarding RegExp

$
0
0

Regular expression with non-literal value

Description

The RegExp constructor was called with a non-literal value. If an adversary were able to supply a malicious regex, they could cause a Regular Expression Denial of Service (ReDoS) against the application. In Node applications, this could cause the entire application to no longer be responsive to other users’ requests.

To remediate this issue, never allow user-supplied regular expressions. Instead, the regular expression should be hardcoded. If this is not possible, consider using an alternative regular expression engine such as node-re2. RE2 is a safe alternative that does not support backtracking, which is what leads to ReDoS.

Example using re2 which does not support backtracking (Note: it is still recommended to never use user-supplied input):

// Import the re2 module
const RE2 = require('re2');

function match(userSuppliedRegex, userInput) {
    // Create a RE2 object with the user supplied regex, this is relatively safe
    // due to RE2 not supporting backtracking which can be abused to cause long running
    // queries
    var re = new RE2(userSuppliedRegex);
    // Execute the regular expression against some userInput
    var result = re.exec(userInput);
    // Work with the result
}

For more information on Regular Expression DoS see:

Medium

  • Tool: SAST
  • Scanner: Semgrep

1 post - 1 participant

Read full topic

Cosmodb with ionic 7

iOS Only - Using 2x storage for downloaded files

$
0
0

I can’t tell if this is a capacitor/Ionic/iOS thing?

When I download files to the DATA directory on my iOS device (but not on Android) using the @capacitor/file-system it uses 2x the storage space. The actual file is the correct size.

When I do this in a simulator and dig into the file system I find that there is a NetworkCache folder that is a duplicate size of the file I just downloaded?!

Who is creating this folder?
Is it iOS?
Is it going to get cleaned up at some point?

When my users download a 1GB file I don’t want it to use 2GB of their storage. But on iOS, that’s what it does and I don’t know how they can reclaim that short of deleting the app?!

What’s really bad is if I delete the file, that storage is reclaimed, but not what’s in NetworkCache folder?! So this completely useless data is un-reclaimable?!

1 post - 1 participant

Read full topic

IonPage doesn't render after transition occasionally (with Ionic React)

$
0
0

Hi.

My name is Fabian, and I have built an Ionic Capacitor React app for both Android and iOS. However, there is an issue that occurs on the iOS version, where the IonPage occasionally fails to render. This issue doesn’t seem to appear on Android.

There are no errors printed to the console when this issue happens, and the url of the failing page is correct, according to the Sarari inspector, so I don’t think it has to do with the router.

Here are some screenshots:

Page transition starting point (user presses the ‘Browse all videos’ button):

What the next page SHOULD look like:

What the next page occassionally looks like, when the error occurs (~10% of the time):

Tapping one of the tab buttons will fix it, and the correct content will then be rendered

Please help me solve this. I’ve tried several things, like: removing everything within the ion-content tags, checking the state at certain points of execution, reworking the sorting, but I am baffled.

Here is the relevant component code that should renders the IonPage:

import {
  IonBackButton,
  IonButtons,
  IonContent,
  IonHeader,
  IonPage,
  IonSearchbar,
  IonTitle,
  IonToolbar,
  useIonViewDidEnter,
  useIonViewWillEnter,
  useIonViewWillLeave,
} from "@ionic/react";
import { useEffect, useMemo, useRef, useState } from "react";
import { useLocation, useParams } from "react-router";
import { Virtuoso } from "react-virtuoso";
import { useAppSelector } from "../../lib/custom-hooks/useAppSelector";
import { useHomeSubRouting } from "../../lib/custom-hooks/useHomeSubRouting";
import { selectAllCpdVideos } from "../../lib/slices/appContentSlice";
import { CPDListLinkOrigin, CPDVideo, FilterListModalType, SortMode } from "../../lib/types";
import { Utils } from "../../lib/utils";
import { selectAppActivity } from "../../lib/slices/appActivitySlice";
import { Keyboard } from "@capacitor/keyboard";
import VideoFilterButton from "../../shared-components/VideoFilterButton";
import VideoFilterModal from "./VideoFilterModal";
import CPDSortModal from "./CPDSortModal";
import VideoCard from "./VideoCard";
import imgDropdownGreen from "../../assets/images/dropdown_green_n.png";

function CPDHubVideoList() {
  console.log("CPDHubVideoList rendering...");

  const homeSubRoute = useHomeSubRouting();
  const location = useLocation();

  const searchInputRef = useRef<HTMLIonSearchbarElement>(null);
  const filtersContainerRef = useRef<HTMLDivElement | null>(null);
  const prevScrollOffset = useRef(0);

  const params = useParams<{ linkOrigin: CPDListLinkOrigin; optionalParam?: string }>(); // TODO optionalParam will be an event id or category
  const decodedOptionalParam = params.optionalParam ? decodeURIComponent(params.optionalParam) : null;

  const appActivity = useAppSelector(selectAppActivity);
  const allVideos = useAppSelector(selectAllCpdVideos);
  const allVideosForCurrentRoute = useMemo(() => filterAllVideosFromLinkOrigin(), [location.pathname]);

  const [filtersContainerOffset, setFiltersContainerOffset] = useState(0);
  const [searchText, setSearchText] = useState("");
  // TODO use generics here instead of selectedCategories, selectedPresenters etc
  const [selectedCategories, setSelectedCategories] = useState<string[]>(
    decodedOptionalParam ? [decodedOptionalParam] : []
  );
  const [selectedPresenters, setSelectedPresenters] = useState<string[]>([]);
  const [selectedDates, setSelectedDates] = useState<string[]>([]);
  const [sortMode, setSortMode] = useState<SortMode>("Last added");
  const [showSortModal, setShowSortModal] = useState(false);
  const [filterListModal, setFilterListModal] = useState<{
    show: boolean;
    type: FilterListModalType;
    allItems: string[];
  }>({
    show: false,
    type: "",
    allItems: [],
  });

  const uniqueCategories = useMemo(() => Utils.getUniqueCategoriesForVideos(allVideos), []);
  const uniquePresenters = useMemo(() => getUniquePresentersForVideos(), []);
  const uniqueDates = useMemo(() => getUniqueDatesForVideos(), []);

  const filteredVideos = filterVideos();

  const pageTitle = useMemo(() => {
    switch (params.linkOrigin) {
      case "bookmarks":
        return "Bookmarked";
      case "history":
        return "History";
      case "recently-added":
        return "Recently added CPD";
      case "top-rated":
        return "Top Rated";
      case "event":
        return decodedOptionalParam;
      default:
        return "";
    }
  }, []);

  const showSearchInput =
    params.linkOrigin === "search" || params.linkOrigin === "browse" || params.linkOrigin === "category";
  const showFilters =
    params.linkOrigin === "search" ||
    params.linkOrigin === "browse" ||
    params.linkOrigin === "top-rated" ||
    params.linkOrigin === "category" ||
    params.linkOrigin === "event";

  useIonViewDidEnter(() => {
    if (params.linkOrigin === "search") {
      searchInputRef.current?.setFocus();
    }
  }, []);

  useIonViewWillEnter(() => {
    if (filtersContainerRef.current) {
      setFiltersContainerOffset(-filtersContainerRef.current.offsetHeight);
    }
  }, []);

  useIonViewWillLeave(() => {
    setFiltersContainerOffset(filtersContainerRef.current?.offsetHeight!);
  }, []);

  function filterAllVideosFromLinkOrigin() {
    switch (params.linkOrigin) {
      case "bookmarks":
        return [...allVideos].filter((vid) => vid.isBookmarked);
      case "history":
        return [...allVideos].filter((vid) => appActivity.map((it) => it.id).includes(vid.id));
      case "recently-added":
        return [...allVideos].sort((a, b) => b.publishedOrder - a.publishedOrder).slice(0, 10);
      case "event":
        return [...allVideos]; // TODO
      case "top-rated":
        return [...allVideos].sort((a, b) => b.likeCount - a.likeCount).slice(0, 10);
      case "category":
        return [...allVideos].filter((vid) => vid.eventCategory === decodedOptionalParam);
      default:
        return [...allVideos];
    }
  }

  function filterVideos() {
    let videosCopy = [...allVideosForCurrentRoute];

    // sort
    if (sortMode === "Last added") {
      videosCopy = sortVideosByLastAdded(videosCopy);
    } else if (sortMode === "Oldest first") {
      videosCopy = sortVideosOldestFirst(videosCopy);
    } else {
      videosCopy = sortVideosAlphabetically(videosCopy);
    }

    videosCopy = applySearch(videosCopy);
    videosCopy = applyCategoryFiltering(videosCopy);
    videosCopy = applyPresenterFiltering(videosCopy);
    videosCopy = applyDatesFiltering(videosCopy);

    return videosCopy;
  }

  function sortVideosByLastAdded(videos: CPDVideo[]) {
    return [...videos].sort((a, b) => b.publishedOrder - a.publishedOrder);
  }

  function sortVideosOldestFirst(videos: CPDVideo[]) {
    return [...videos].sort((a, b) => a.publishedOrder - b.publishedOrder);
  }

  function sortVideosAlphabetically(videos: CPDVideo[]) {
    return [...videos].sort((a, b) => {
      return a.title.localeCompare(b.title);
    });
  }

  function applySearch(videos: CPDVideo[]) {
    const trimmedText = searchText.toLowerCase().trim();
    if (trimmedText === "") {
      return videos;
    }

    const searched = videos.filter((vid) => {
      return (
        vid.title.toLowerCase().includes(trimmedText) ||
        vid.eventType.toLowerCase().includes(trimmedText) ||
        vid.eventCategory.toLowerCase().includes(trimmedText) ||
        vid.shortDescription.toLowerCase().includes(trimmedText) ||
        vid.presenters.join("").toLowerCase().includes(trimmedText)
      );
    });

    return searched;
  }

  function applyCategoryFiltering(videos: CPDVideo[]) {
    if (!selectedCategories.length) {
      return videos;
    }

    return videos.filter((vid) => selectedCategories.includes(vid.eventCategory));
  }

  function applyPresenterFiltering(videos: CPDVideo[]) {
    if (!selectedPresenters.length) {
      return videos;
    }

    return videos.filter((vid) => {
      return vid.presenters.some((presenterOfVideo) => selectedPresenters.includes(presenterOfVideo));
    });
  }

  function applyDatesFiltering(videos: CPDVideo[]) {
    if (!selectedDates.length) {
      return videos;
    }

    return videos.filter((vid) => selectedDates.includes(vid.eventDate));
  }

  // TODO use generics instead?
  function determineSelectedItemsForFilterModal() {
    switch (filterListModal.type) {
      case "Categories":
        return selectedCategories;
      case "Presenters":
        return selectedPresenters;
      case "Dates":
        return selectedDates;
      default:
        return [];
    }
  }

  function clearSelectedItems() {
    switch (filterListModal.type) {
      case "Categories":
        return setSelectedCategories([]);
      case "Presenters":
        return setSelectedPresenters([]);
      case "Dates":
        return setSelectedDates([]);
    }
  }

  function getUniquePresentersForVideos() {
    const uniqueValues = allVideos
      .flatMap((vid) => vid.presenters)
      .filter((item, index, arr) => arr.indexOf(item) === index);
    return uniqueValues.sort((a, b) => a.localeCompare(b)).filter((it) => it !== "");
  }

  // TODO
  function getUniqueDatesForVideos() {
    const uniqueValues = allVideos
      .map((vid) => vid.eventDate)
      .filter((item, index, arr) => arr.indexOf(item) === index);

    return uniqueValues;
  }

  // show filters container if scrolling up, or scroll position is near top (to work well with iOS bounce). otherwise, hide the filters container
  function handleContentScroll(scrollTop: number) {
    if (filteredVideos.length < 4) return; // don't do anything if there's only a couple of videos to show

    var currentScrollPos = scrollTop;
    if (prevScrollOffset.current > currentScrollPos || currentScrollPos < 10) {
      setFiltersContainerOffset(-filtersContainerRef.current?.offsetHeight!);
    } else {
      setFiltersContainerOffset(filtersContainerRef.current?.offsetHeight!);
    }
    prevScrollOffset.current = currentScrollPos;
  }

  return (
    <IonPage>
      <IonHeader className={"ion-no-border"}>
        <IonToolbar className="t-border">
          <IonButtons
            slot="start"
            class="mr-6"
            style={{
              // Ionic docs recommend using ion-searchbar as the only child to ion-toolbar, but we don't want to do that - which causes back buton misalignment.
              // Add these margins so that the back button is vertically aligned to the centre, like other back buttons. This fix should only be implemented when using a search bar.
              marginTop: showSearchInput ? "var(--padding-top)" : 0,
              marginBottom: showSearchInput ? "var(--padding-bottom)" : 0,
            }}
          >
            <IonBackButton defaultHref={homeSubRoute ? "/app/home/cpd-hub" : "/app/cpd-hub"} />
          </IonButtons>
          {/* TODO fix slight shift in the back button when using this searchbar in the toolbar */}
          {showSearchInput ? (
            <IonSearchbar
              id="video-list-searchbar"
              ref={searchInputRef}
              value={searchText}
              placeholder="Search CPD Hub"
              onIonInput={(e) => setSearchText(e.detail.value!)}
              className="font-normal text-black text-17 leading-27"
            />
          ) : (
            <IonTitle>{pageTitle}</IonTitle>
          )}
        </IonToolbar>
        <div className="relative">
          <div
            className="bg-grey-80 w-full absolute"
            style={{
              height: 300, // number doesn't matter much, just make it high so the background is covered
              bottom: filtersContainerOffset,
            }}
          />
          <div
            ref={filtersContainerRef}
            className="absolute w-full"
            style={{ transition: "bottom 0.2s", bottom: filtersContainerOffset }}
          >
            {showFilters && (
              <div className="t-border bg-grey-80 flex t-border p-2 gap-3 overflow-scroll">
                <VideoFilterButton
                  label="Category"
                  handleClick={() => setFilterListModal({ show: true, type: "Categories", allItems: uniqueCategories })}
                  selectedItemsInFilter={selectedCategories.length}
                />
                <VideoFilterButton
                  label="Presenter"
                  handleClick={() => setFilterListModal({ show: true, type: "Presenters", allItems: uniquePresenters })}
                  selectedItemsInFilter={selectedPresenters.length}
                />
                <VideoFilterButton
                  label="Date"
                  handleClick={() => setFilterListModal({ show: true, type: "Dates", allItems: uniqueDates })}
                  selectedItemsInFilter={selectedDates.length}
                />
              </div>
            )}
            <div
              className="flex justify-between items-center p-3 bg-white"
              style={{ borderBottom: "solid 2px var(--grey-30)" }}
            >
              <div className="flex items-center">
                <div className="text-13 font-semibold text-grey-70">Sort by: &nbsp;</div>
                <button onClick={() => setShowSortModal(true)} className="flex items-center">
                  <div className="text-13 font-semibold text-green-30">{sortMode}</div>
                  <img width={24} height={24} src={imgDropdownGreen} style={{ marginTop: "-4px" }} />
                </button>
              </div>
              <div className="text-13 font-semibold text-grey-70">{`${filteredVideos.length} result${
                filteredVideos.length > 1 ? "s" : ""
              }`}</div>
            </div>
          </div>
        </div>
      </IonHeader>
      <IonContent style={{ "--background": "var(--grey-20)" }} onTouchStart={(e) => Keyboard.hide()}>
        <Virtuoso
          className="t-border"
          data={filteredVideos}
          onScroll={(e) => handleContentScroll(e.currentTarget.scrollTop)}
          itemContent={(index, video) => {
            return (
              // applying padding directly to the virtuoso style prop won't work, so add padding for first item here
              <div style={{ paddingTop: index === 0 ? filtersContainerRef.current?.clientHeight! : "" }}>
                <VideoCard video={video} guestVersion={false} searchText={searchText} />
              </div>
            );
          }}
        />
        <CPDSortModal
          showModal={showSortModal}
          handleClose={() => setShowSortModal(false)}
          handleSortChange={(newSortMode) => setSortMode(newSortMode)}
          currentSortMode={sortMode}
        />
        <VideoFilterModal
          show={filterListModal.show}
          type={filterListModal.type}
          allItems={filterListModal.allItems}
          selectedItems={determineSelectedItemsForFilterModal()}
          resultsCount={filteredVideos.length}
          handleReset={() => clearSelectedItems()}
          handleClose={() => setFilterListModal({ show: false, type: "", allItems: [] })}
          handleSelection={(selectedItem) => {
            switch (filterListModal.type) {
              case "Categories":
                if (selectedCategories.includes(selectedItem)) {
                  // remove from cat list
                  const newItems = [...selectedCategories].filter((cat) => cat !== selectedItem);
                  setSelectedCategories(newItems);
                } else {
                  // add item to cat list
                  setSelectedCategories([...selectedCategories, selectedItem]);
                }
                break;
              case "Presenters":
                if (selectedPresenters.includes(selectedItem)) {
                  const newItems = [...selectedPresenters].filter((cat) => cat !== selectedItem);
                  setSelectedPresenters(newItems);
                } else {
                  setSelectedPresenters([...selectedPresenters, selectedItem]);
                }
                break;
              case "Dates":
                if (selectedDates.includes(selectedItem)) {
                  const newItems = [...selectedDates].filter((cat) => cat !== selectedItem);
                  setSelectedDates(newItems);
                } else {
                  setSelectedDates([...selectedDates, selectedItem]);
                }
                break;
              default:
                throw new Error("Filter type not found");
            }
          }}
        />
      </IonContent>
    </IonPage>
  );
}

export default CPDHubVideoList;

Thanks for any help!

Fabian

3 posts - 2 participants

Read full topic

Viewing all 70958 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>