Indicator Glitch in React native scrollspy

I am experiencing an issue with the tab indicator on Android when tabs autoscroll. The indicator disappears during the autoscroll process, and when I manually scroll the tabs back to their initial position, the indicator reappears at that position.

This issue does not occur on iOS, where the code functions as expected. I have attempted several solutions, such as removing the indicator from the ListHeaderComponent and displaying it externally, but I have not been able to resolve the problem.

I have included both the code and a GIF demonstrating the behavior. If anyone has encountered a similar issue or has any suggestions for resolving this, I would greatly appreciate your insights.

Thank you in advance for your help!

import { ThemedText } from "@/components/ThemedText";
import { ThemedView } from "@/components/ThemedView";
import { faker } from "@faker-js/faker";
import React, { useEffect, useRef, useState, useCallback } from "react";
import {
  FlatList,
  Image,
  LayoutRectangle,
  SectionList,
  StyleSheet,
  TouchableOpacity,
  useWindowDimensions,
  ViewToken,
} from "react-native";
import Animated, {
  AnimatedProps,
  interpolate,
  runOnJS,
  SharedValue,
  useAnimatedScrollHandler,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from "react-native-reanimated";
import getItemLayout from "react-native-get-item-layout-section-list";
import { useSafeAreaInsets } from "react-native-safe-area-context";

faker.seed(123);
const AnimatedSectionList = Animated.createAnimatedComponent(SectionList);
const getRandomData = () =>
  [...Array(faker.number.int({ min: 2, max: 5 }))].map(() => ({
    key: faker.string.uuid(),
    song: faker.music.songName(),
    artist: faker.music.artist(),
    album: faker.music.album(),
    cover: faker.image.personPortrait(),
  }));

const _sections = [...Array(5).keys()].map((index) => ({
  key: faker.string.uuid(),
  title: faker.music.genre(),
  data: getRandomData(),
  sectionIndex: index,
}));

const _spacing = 12;
const _indicatorSize = 4;
const ITEM_HEIGHT = 99;
const SECTION_HEADER_HEIGHT = 46;

const buildGetItemLayout = getItemLayout({
  getItemHeight: ITEM_HEIGHT,
  getSectionHeaderHeight: SECTION_HEADER_HEIGHT,
});

type TabsLayout = Record<number, LayoutRectangle>;

// Memoized list item component
const DummyItem = React.memo(
  ({ item }: { item:any}) => (
    <ThemedView style={styles.itemContainer}>
      <ThemedView style={{ gap: _spacing, flexDirection: "row" }}>
        <Image
          source={{ uri: item.cover }}
          style={{
            height: 50,
            aspectRatio: 1,
            borderRadius: _spacing / 2,
            borderWidth: 2,
            borderColor: "rgba(255,255,255,0.5)",
          }}
        />
        <ThemedView style={{ flex: 1, justifyContent: "space-between" }}>
          <ThemedText style={styles.artistText}>{item?.artist}</ThemedText>
          <ThemedText style={styles.songText}>{item?.song}</ThemedText>
          <ThemedText style={styles.albumText}>{item?.album}</ThemedText>
        </ThemedView>
      </ThemedView>
    </ThemedView>
  )
);

function Indicator({ measurements }: { measurements: LayoutRectangle }) {

  const _stylez = useAnimatedStyle(() => ({
    width: withTiming(measurements.width, { duration: 150 }),
    left: withTiming(measurements.x, { duration: 150 }),
    top: measurements.height,
  }));

  return <Animated.View style={[styles.indicator, _stylez]} />;
}

const Tabs = React.memo(
  ({
    activeSectionIndex,
    onTabPress,
  }: {
    activeSectionIndex: number;
    onTabPress: (index: number) => void;
  }) => {
    const _tabsLayout = useRef<TabsLayout>({});
    
    const ref = useRef<FlatList>(null);
    const [isDoneMeasuring, setIsDoneMeasuring] = useState(false);

    const scrollToIndex = useCallback((index: number) => {
      ref.current?.scrollToIndex({
        index,
        animated: true,
        viewPosition: 0.5,
      });
    }, []);

    useEffect(() => {
      scrollToIndex(activeSectionIndex);
    }, [activeSectionIndex, scrollToIndex]);

    const renderTabItem = useCallback(
      ({ item, index }: { item: (typeof _sections)[0]; index: number }) => (
        <TouchableOpacity onPress={() => onTabPress(index)}>
          <ThemedView style={styles.tabItem}>
            <ThemedText style={styles.tabText}>{item?.title}</ThemedText>
          </ThemedView>
        </TouchableOpacity>
      ),
      [onTabPress]
    );

    return (
      <FlatList
        ref={ref}
        data={_sections}
        initialNumToRender={5}
        maxToRenderPerBatch={5}
        windowSize={21}
        getItemLayout={(_, index) => ({
          length: _tabsLayout.current[index]?.width || 0,
          offset: _tabsLayout.current[index]?.x || 0,
          index,
        })}
        CellRendererComponent={({ children, index, ...rest }) => (
          <ThemedView
            {...rest}
            onLayout={(e) => {
              _tabsLayout.current[index] = e.nativeEvent.layout;
              if (
                Object.keys(_tabsLayout.current).length === _sections.length &&
                !isDoneMeasuring
              ) {
                setIsDoneMeasuring(true);
              }              
            }}
          >
            {children}
          </ThemedView>
        )}
        renderItem={renderTabItem}
        horizontal
        style={styles.tabsContainer}
        showsHorizontalScrollIndicator={false}
        scrollEventThrottle={16}
        contentContainerStyle={styles.tabsContent}
        ListHeaderComponent={
          isDoneMeasuring ? (
            <Indicator measurements={_tabsLayout.current[activeSectionIndex]} />
          ) : null
        }
        ListHeaderComponentStyle={styles.indicatorPosition}
      />
    );
  }
);

const _headerHeight = 350;
const _headerTabsHeight = 49;
const _headerTopNav = 80;
const _headerImageHeight = _headerHeight - _headerTabsHeight;
const _topThreshold = _headerHeight - _headerTopNav;

const ScrollHeader = React.memo(
  ({
    selectedSection,
    onTabPress,
    scrollY,
  }: {
    selectedSection: number;
    onTabPress: (index: number) => void;
    scrollY: SharedValue<number>;
  }) => {
    const { top } = useSafeAreaInsets();

    const headerStylez = useAnimatedStyle(() => ({
      transform: [
        {
          translateY: interpolate(
            scrollY.value,
            [-1, 0, 1, _topThreshold - 1, _topThreshold],
            [1, 0, -1, -_topThreshold, -_topThreshold]
          ),
        },
      ],
    }));

    const imageStyles = useAnimatedStyle(() => ({
      opacity: interpolate(
        scrollY.value,
        [-1, 0, _headerImageHeight - 1, _headerImageHeight],
        [1, 1, 0.3, 0]
      ),
      transform: [
        {
          scale: interpolate(
            scrollY.value,
            [-1, 0, 1],
            [1 + 1 / _headerHeight, 1, 1]
          ),
        },
      ],
    }));

    return (
      <Animated.View style={[styles.headerContainer, headerStylez]}>
        <Animated.Image
          source={{
            uri: "https://images.pexels.com/photos/7497788/pexels-photo-7497788.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
          }}
          style={[styles.headerImage, imageStyles]}
          resizeMode="cover"
        />
        <Tabs activeSectionIndex={selectedSection} onTabPress={onTabPress} />
      </Animated.View>
    );
  }
);

const Home = () => {
  const [selectedSection, setSelectedSection] = useState(0);
  const activeSectionIndexRef = useRef(0);
  const scrollingFromTabPress = useRef(false);
  const sectionRef = useRef<SectionList>(null);
  const { height } = useWindowDimensions();
  const scrollY = useSharedValue(0);

  const setScrollingFromTabPress = useCallback((value: boolean) => {
    scrollingFromTabPress.current = value;
  }, []);

  const onScroll = useAnimatedScrollHandler({
    onScroll: (e) => {
      scrollY.value = e.contentOffset.y;
    },
    onBeginDrag: () => {
      runOnJS(setScrollingFromTabPress)(false);
    },
  });

  const scrollToSection = useCallback((index: number) => {
    sectionRef.current?.scrollToLocation({
      itemIndex: 0,
      sectionIndex: index,
      animated: true,
      viewOffset: 0,
      viewPosition: 0,
    });
  }, []);

  const handleViewableItemsChanged = useCallback(
    ({ viewableItems }: { viewableItems: ViewToken[] }) => {
      if (scrollingFromTabPress.current) return;

      const section = viewableItems[0]?.section;
      if (!section) return;

      const { sectionIndex } = section as (typeof _sections)[0];
      if (sectionIndex !== selectedSection) {
        activeSectionIndexRef.current = sectionIndex;
        setSelectedSection(sectionIndex);
      }
    },
    [selectedSection]
  );

  const viewabilityConfig = useRef({
    minimumViewTime: 50,
    itemVisiblePercentThreshold: 50,
    waitForInteraction: true,
  }).current;

  return (
    <ThemedView style={styles.container}>
      <AnimatedSectionList
        ref={sectionRef as any}
        sections={_sections}
        keyExtractor={(item:any) => item.key}
        renderItem={({ item }) => <DummyItem item={item} />}
        contentContainerStyle={[
          styles.sectionListStyle,
          { paddingBottom: height / 3, paddingTop: _headerHeight },
        ]}
        renderSectionHeader={({ section: { title } }:{section:any}) => (
          <ThemedView style={styles.sectionHeader}>
            <ThemedText style={styles.sectionHeaderText}>{title}</ThemedText>
          </ThemedView>
        )}
        getItemLayout={buildGetItemLayout}
        onViewableItemsChanged={handleViewableItemsChanged}
        viewabilityConfig={viewabilityConfig}
        onScroll={onScroll}
        scrollEventThrottle={16}
        initialNumToRender={10}
        maxToRenderPerBatch={10}
        windowSize={21}
        bounces={false}
        removeClippedSubviews={true}
        stickyHeaderHiddenOnScroll
      />
      <ScrollHeader
        scrollY={scrollY}
        onTabPress={(index) => {
          if (selectedSection !== index) {
            setSelectedSection(index);
            scrollToSection(index);
            scrollingFromTabPress.current = true;
          }
        }}
        selectedSection={selectedSection}
      />
    </ThemedView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  itemContainer: {
    padding: _spacing,
    borderBottomWidth: 1,
    borderBottomColor: "rgba(0,0,0,0.05)",
  },
  songText: {
    fontSize: 16,
    fontWeight: "bold",
  },
  albumText: {
    fontSize: 10,
    opacity: 0.3,
  },
  sectionListStyle: {},
  artistText: {
    fontSize: 14,
    opacity: 0.3,
  },
  sectionHeader: {
    backgroundColor: "#fff",
    paddingVertical: _spacing * 2,
    paddingHorizontal: _spacing,
  },
  sectionHeaderText: {
    fontSize: 18,
    fontWeight: "700",
  },
  indicator: {
    height: _indicatorSize,
    backgroundColor: "#000",
  },
  tabsContainer: {
    flexGrow: 0,
    paddingBottom: _indicatorSize,
    height: _headerTabsHeight,
  },
  tabsContent: {
    gap: _spacing * 2,
    paddingHorizontal: _spacing,
  },
  indicatorPosition: {
    position: "absolute",
  },
  tabItem: {
    paddingVertical: _spacing,
  },
  tabText: {
    fontWeight: "600",
  },
  headerContainer: {
    height: _headerHeight,
    position: "absolute",
    backgroundColor: "#fff",
    top: 0,
    left: 0,
    right: 0,
  },
  headerImage: {
    height: _headerImageHeight,
    width: "100%",
  },
});

export default Home;

enter image description here

Issue after Upgrading to Laravel 11: Undefined array key “driver”

I followed all the upgrade guide requirements, but when I run php artisan, I get the following error:

Undefined array key "driver"

  at vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemServiceProvider.php:117
    113▕      * @return bool
    114▕      */
    115▕     protected function shouldServeFiles(array $config)
    116▕     {
  ➜ 117▕         return $config['driver'] === 'local' && ($config['serve'] ?? false);
    118▕     }
    119▕ 
    120▕     /**
    121▕      * Get the default file driver.

I checked the vendor files and found the function responsible:

/**
 * Determine if the disk is serveable.
 *
 * @param  array  $config
 * @return bool
 */
protected function shouldServeFiles(array $config)
{
    return $config['driver'] === 'local' && ($config['serve'] ?? false);
}

To debug, I dumped the $config and got:

array:3 [
  "driver" => "local"
  "root" => "/var/www/html/storage/app"
  "throw" => false
]

When I dd() the full condition, it returns false:

dd($config['driver'] === 'local' && ($config['serve'] ?? false));

If I modify the vendor file to return false, php artisan starts working again—but obviously, modifying vendor files isn’t a proper solution.

My filestems.php file

        's3' => [
            'blog' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'blog',
                'url' => env('AWS_URL').'/blog',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
            'verifications' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'verifications',
                'url' => env('AWS_URL').'/verifications',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
            'contracts' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'contracts',
                'url' => env('AWS_URL').'/contracts',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
            'preliminary' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'preliminary',
                'url' => env('AWS_URL').'/preliminary',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
            'temporary' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'temporary',
                'url' => env('AWS_URL').'/temporary',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
            'internal' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'internal',
                'url' => env('AWS_URL').'/internal',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
            'listing-images' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'listing-images',
                'url' => env('AWS_URL').'/listing-images',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
            'payout-invoices' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'payout-invoices',
                'url' => env('AWS_URL').'/payout-invoices',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
            'listing-payment-invoices' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION'),
                'bucket' => 'listing-payment-invoices',
                'url' => env('AWS_URL').'/listing-payment-invoices',
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
                'throw' => true,
            ],
        ],

Has anyone encountered this issue before? Any insights on how to fix it properly?

Need to enable wincache DLL extension into IIS & PHP 8.3 version?

We are trying to install & enable the wincache dll extension into PHP 8.3 version but it is not enable. We added the file and enable extension=php_wincache.dll in php.ini file. But, when we see the PHP info, the wincache modules is not show in the details.

Php version :8.3.19 NTS (non thread safe)
Windows IIS

Could you please provide us non thread safe wincache DLL file and provide the points to install into the IIS server (PHP 8.3)

Thanks,

Create shortcode for each dimension property based on product ID in WooCommerce

Summarize:
Woocommerce product dimensions are length, width and height
Scope of this question is to create a shortcode for each product dimension property individually based on product ID.

Problem:
I found many sources and no one split the dimensions in three single shortcode attribute, like in Display WooCommerce Product Dimensions via a Shortcode answer thread.

This is an example on how Display WooCommerce Product Dimensions via a Shortcode.
I don’t know how to show attribute in near.

Description:
Add where needed a shortcode for Lenght
[user_meta id="35" key="lenght"]
Add where needed a shortcode for Width
[user_meta id="35" key="width"]
Add where needed a shortcode for Height
[user_meta id="35" key="height"]

Expections:
Something like this with a shortcode foreach dimensions

add_action( 'woocommerce_after_shop_loop_item', 'aman_show_product_dimensions', 20 );
  
function aman_show_product_dimensions() {
   global $product;
   $dimensions = $product->get_dimensions();
   if ( ! empty( $dimensions ) ) {
      echo '<div class="dimensions"><b>Height:</b> ' . $product->get_height() . get_option( 'woocommerce_dimension_unit' );
      echo '<br><b>Width:</b> ' . $product->get_width() . get_option( 'woocommerce_dimension_unit' );
      echo '<br><b>Length:</b> ' . $product->get_length() . get_option( 'woocommerce_dimension_unit' );
      echo '</div>';        
   }
}

Jquery compatibility issues with chrome select list options

This is working fine with brave but in chrome only some options are populated and most are missing.
Im fetching with jquery and i want to populate the data in an hierarchical manner based on the component_code and parent_component_code.


    $.ajax({
            type: "get",
            url: "/get-components/" + code,
            success: function (response) {
                let data = response;
                const createSelectOptions = (data, parentCode) => {
                    const options = [];
                    $.each(data, (index, item) => {
                        if (item.parent_component_code === parentCode) {
                            if (
                                data.some(
                                    (child) =>
                                        child.parent_component_code ===
                                        item.component_code
                                )
                            ) {
                                options.push(
                                    `<optgroup label="${item.component_desc}">`
                                );
                                options.push(
                                    ...createSelectOptions(
                                        data,
                                        item.component_code
                                    )
                                );
                                options.push(`</optgroup>`);
                            } else {
                                options.push(
                                    `<option value="${item.component_code}">${item.component_desc}</option>`
                                );
                            }
                        }
                    });
                    return options;
                };

                const selectOptions = createSelectOptions(data, null);
                $("#component_code").html(
                    [
                        `<option value="" selected disabled>--Select Component--</option>`,
                        ...selectOptions,
                    ].join("")
                );

                $("#component_code").prop("disabled", false);
            },
        });

Cannot add Vercel Toolbar to Next project

I’m following this guide, and am getting this error from Next. The URL referenced isn’t helping.

 ⚠ Invalid next.config.mjs options detected: 
 ⚠     Expected object, received string
 ⚠ See more info here: https://nextjs.org/docs/messages/invalid-next-config

My code looks like:

import withVercelToolbar from '@vercel/toolbar/plugins/next'

let nextConfig = {}

export default withVercelToolbar(nextConfig)

When combining with Sentry I get the error:

TypeError: Cannot set properties of undefined (setting 'clientTraceMetadata')

Choosing a framework for the frontend components: Dialogs, Data Tables, Buttons, Alerts [closed]

I have a project already written in Vanilla Javascript.

The project is extensively used in the company business process.

There are around 20 pages with tables and simple Javascript dialogs and logics. Dialogs are opening in showModal() mode. Also there are dialogs over dialogs and so on.
There are several pages using datatables.js with jQuery.

And now I have a doubt what is the best option for further development. I used ReactJS before in other projects, and I think it would be the good option. On the other side, ReactJS hard to involve into current infrastructure. I am not sure if it will be friendly with jQuery and datatables.js. Also it’s a question, how to connect current project with server side generated page templates with new pages with routing in React.js.

Currently, I chose just a Vanilla JS with MVC structure which will fit the best without any project production issues.

Please tell me your opinion or some stories from past experience. Just don’t want to reinvent bicycle, may be some framework or option I just missed or did not know about.

problem in updating new images when previous images exists

I am stuck in the problem for few days, i am trying to update images, but the problem is that, when there are previous images exists then new images are not appending with previous images, new images only adds when no previous image exists, someone please help me to fix this problem.

here is my html an js code…

       <div class="row mlr-0 ptb-15 bdr-dim mb-10 text-center">
<div class="col plr-0 inline-items">
    @php
        $post_images = explode(',', $y_post->post_images ?? '');
        $image_count = count(array_filter($post_images));
    @endphp
    <div id="image-preview-container">
        @foreach($post_images as $index => $image)
            @if(!empty($image))
                <div class="image-box" data-index="{{ $index+1 }}" style="position: relative;display: inline-block;margin: 5px;">
                    <img class="previewimg  mr-0" src="{{ asset('uploads/' . $image) }}" style="width: 200px;height: 200px;object-fit: cover;border: 1px solid lightgray;border-radius: 5px;padding: 5px;">
                    <span class="delete-edit-img remove-image" alt="delete" style="position: absolute;top: 10;right: 10;cursor: pointer;background: white;border-radius: 60%; padding: 0px 10px;">X</span>
                </div>
            @endif
        @endforeach
    </div>

    

    <input type="hidden" id="image-count" value="{{ $image_count }}">

    
    <img src="{{ asset('images/PostProperty/upload-image.png') }}" id="add_images_label" class="upload img-btn" style="height: 50px;width: 50px;border: none;@if($image_count >= 5) display: none;@endif">

    <!-- Hidden file input -->
    <input type="file" id="image-upload-input" class="post-img-file" name="file[]" multiple style="display: none;">
 </div>
</div>                                             

 <script>
  $(document).ready(function () {
   var max_limit = 5; // Maximum images allowed
   var img_count = parseInt($('#image-count').val());

   // Open hidden file input when clicking "Add Images" button
   $(document).on('click', '#add_images_label', function () {
    $('#image-upload-input').click();
    });

    $(document).on('change', '#image-upload-input', function (event) {
    var files = event.target.files;

    if (img_count + files.length > max_limit) {
        alert('You can only upload up to ' + max_limit + ' images.');
        return;
    }

    $.each(files, function (index, file) {
        if (img_count >= max_limit) return false; // Stop adding images if limit is reached

        var reader = new FileReader();
        reader.onload = function (e) {
            img_count++;

            var imageElement = `
                <div class="image-box" data-index="${img_count}" style="position: 
                  relative;display: inline-block;margin: 5px;">
                    <img class="previewimg  mr-0" src="${e.target.result}" style="width: 
                     200px;height: 200px;object-fit: cover;border: 1px solid lightgray;border- 
                      radius: 5px;padding: 5px;">
                       <span class="delete-edit-img remove-image" alt="delete" 
                        style="position: 
                         absolute;top: 10;right: 10;cursor: pointer;background: white;border- 
                          radius: 60%; padding: 0px 10px;">X</span>
                </div>
            `;
            $('#image-preview-container').append(imageElement);
            $('#image-count').val(img_count);
        };
        reader.readAsDataURL(file);
    });

    // Hide "Add Images" button if limit reached
    if (img_count >= max_limit) {
        $('#add_images_label').hide();
    }
});

// Remove image when clicking delete button
$(document).on('click', '.remove-image', function () {
    $(this).closest('.image-box').remove();
    img_count--;

    $('#image-count').val(img_count);

    // Reassign indexes after deletion
    $('.image-box').each(function (index) {
        $(this).attr('data-index', index + 1);
    });

    // Show "Add Images" button if below limit
    if (img_count < max_limit) {
        $('#add_images_label').show();
    }
 });
});
</script>

.text() and .html is not working in my code [closed]

I dont know why it’s not working because I try to log it and this is the result

Updating message: 68
chat:1641 test edit 54
chat:1642 test edit 53
chat:1644 test edit 54

and this is the actual code

function updateMessageRow(messageRow, message) {
    console.log('Updating message:', message.message_id);
    if (messageRow.length) {
        
        const bubble = messageRow.find('.bubble'); 
        const timestamp = messageRow.find('span');

        // Update the content
        console.log(message.message);
        console.log(bubble.find('p').html());
        bubble.find('p').html(message.message);
        console.log(bubble.find('p').html());
        if (timestamp.length > 0) {
            timestamp.text(message.created_at);
        }

        messageRow.hide().show();
    }
    scrollToBottom();
}

This is the image for UI

I also tried append the message to the bubble and still not work, I don’t think that the message value is incorrect because in my console.log I’m getting the correct value

This is where the updateMessageRow function is called

function reloadChatMessage() {
    $.ajax({
        url: "{{ route('reloadobs.chat.message') }}",
        type: "POST",
        data: {
            _token: "{{ csrf_token() }}", // CSRF token for Laravel
            chatUpdate: JSON.stringify(chatUpdate) // Send the last update data
        },
        success: function(response) {
            if (response.status === 'initial_load') {
                // Initial load: Update the entire chat list
                chatUpdate = response.chatUpdate;
                if (response.messages && response.messages.length > 0) {
                    response.messages.forEach(message => {
                        appendMessage(message);
                    });
                    scrollToBottom();
                }
            } else if (response.status === 'count_changed') {
                // Handle new chats and deleted chats
                chatUpdate = response.chatUpdate;
                // Add new chats to the list
                if (response.newMessages && response.newMessages.length > 0) {
                    response.newMessages.forEach(message => {
                        appendMessage(message);
                    });
                    scrollToBottom();
                }

                // Remove deleted chats from the list
                if (response.deletedMessageIds && response.deletedMessageIds.length > 0) {
                    response.deletedMessageIds.forEach(messageId => {
                        $(`#messageRow_${messageId}`).remove(); // Remove the chat by ID
                    });
                }
            } else if (response.status === 'chat_updated') {
                chatUpdate = response.chatUpdate;
                if (response.messages) {
                    const message = response.messages;
                    console.log(message);
                    const messageRow = $(`#messageRow_${message.message_id}`);
                    if (messageRow.length) {
                        updateMessageRow(messageRow, message);
                    } else {
                        appendMessage(message);
                    }
                    scrollToBottom();
                }
            } else if (response.status === 'no_changes') {
                // No changes detected
                chatUpdate = response.chatUpdate;
            } else {
                console.log('Error:', response.message);
            }
        },
        error: function(xhr, status, error) {
            console.error('Error occurred:', xhr.responseText);
            console.error('Error occurred:', status);
            console.error('Error occurred:', error);
        }
    });
}

The purpose of updateMessageRow is to change the value of row that edited using messageRow and the message new value

and for the php controller is here:

public function reloadChatMessage(Request $request){
    // Retrieve all tasks from the database.
    $userId = Auth::id();

    // Fetch the chats where the user is a participant, sorted by the last message time
    $chatParticipant = ChatParticipant::where('chat_participants.user_id', $userId)->where('is_here', 1)->first();

    $messagesResult = [];
    if (!$chatParticipant) {
        return response()->json([
            'status'     => 'no_changes',
            'chatUpdate' => $request->chatUpdate,
            'messages'      => $messagesResult
        ]);
    }

    $chatId = $chatParticipant->chat_id;
    $messages = Message::where('chat_id', $chatId)->get();
    foreach ($messages as $message) {
        $formattedTime = Carbon::parse($message->created_at);
        $formattedTime = $formattedTime->isToday()
            ? $formattedTime->format('h:i A')
            : $formattedTime->format('h:i A, M d');

        $messagesResult[] = [
            'message_id' => $message->id,
            'chat_id' => $chatId,
            'user_id' => $message->user_id,
            'message' => $message->message,
            'status' => $message->status,
            'last_seen' => $message->last_seen,
            'created_at' => $formattedTime,
            'photo' => $message->user->photo,
            'my_id' => $userId,
            'updated_at' => $message->updated_at->toIso8601String()
        ];
    }


    // Get client's last snapshot
    $currentSnapshot = [];
    foreach ($messagesResult as $message) {
        $currentSnapshot[$message['message_id']] = $message['updated_at'];
    }

    $clientSnapshot = json_decode($request->chatUpdate, true);

    // If no client data was provided, treat this as the initial load.
    if (!$clientSnapshot || !is_array($clientSnapshot)) {
        return response()->json([
            'status'     => 'initial_load',
            'chatUpdate' => $currentSnapshot,
            'messages'      => $messagesResult
        ]);
    }

    if (count($currentSnapshot) !== count($clientSnapshot)) {
        // Find new chats (chats in $currentSnapshot but not in $clientSnapshot)
        $newMessages = [];
        foreach ($currentSnapshot as $messageId => $updatedAt) {
            if (!isset($clientSnapshot[$messageId])) {
                $newMessage = collect($messagesResult)->firstWhere('message_id', $messageId);
                if ($newMessage) {
                    $newMessages[] = $newMessage;
                }
            }
        }

        // Find deleted chats (chats in $clientSnapshot but not in $currentSnapshot)
        $deletedMessageIds = [];
        foreach ($clientSnapshot as $messageId => $updatedAt) {
            if (!isset($currentSnapshot[$messageId])) {
                $deletedMessageIds[] = $messageId;
            }
        }

        return response()->json([
            'status'          => 'count_changed',
            'chatUpdate'      => $currentSnapshot,
            'newMessages'        => $newMessages,       // New chats to add
            'deletedMessageIds'  => $deletedMessageIds  // Chat IDs to remove
        ]);
    }

    foreach ($currentSnapshot as $messageId => $serverUpdatedAt) {
        if (!isset($clientSnapshot[$messageId]) || $clientSnapshot[$messageId] !== $serverUpdatedAt) {
            $updateMessage = collect($messagesResult)->firstWhere('message_id', $messageId);
            if ($updateMessage) {
                return response()->json([
                    'status'     => 'chat_updated',
                    'chatUpdate' => $currentSnapshot,
                    'messages'       => $updateMessage // Return only the updated chat
                ]);
            }
        }
    }


    // No changes detected.
    return response()->json([
        'status'     => 'no_changes',
        'chatUpdate' => $currentSnapshot,
        'messages'      => $messagesResult
    ]);
}

I don’t see any problem in the controller and where the function updateMessage() is call because the only problem is the .text() or .html() is not overriding the text inside.

and also this is the updateMessageRow before:

function updateMessageRow(messageRow, message) {
    console.log('Updating message:', message.message_id);
    const $lastGroup = $('#messagesContainer li:last');
    const lastGroupUserId = $lastGroup.data('user-id');

    if ($lastGroup.length > 0 && lastGroupUserId === message.user_id) {
        // Append to existing group
        const $content = $lastGroup.find('.content');
        console.log('Updating message in if statements:', message.message_id);
        // Remove timestamp from previous last message
        const $lastMessage = $content.find('.message:last');
        $lastMessage.find('span').remove();

        messageRow.html(`
            <div class="bubble nopoint">
                <p>${message.message}</p>
            </div>
            <span>${message.created_at}</span>
        `);
    } else {
        console.log('Updating message in else statements:', message.message_id);
        messageRow.html(`
            <div class="bubble">
                <p>${message.message}</p>
            </div>
            <span>${message.created_at}</span>
        `);
    }
    scrollToBottom();
}

one time this messageRow.html() work in else but when the code goes to if the messageRow.html is not working there.

How to Structure and Organize a GraphQL Apollo Server Project for Professional Development? [closed]

I am currently learning GraphQL with Apollo Server, and I am quite new to the technology. I am following the official Apollo Server documentation (with my additions) but want to improve my code structure and learn how professional developers structure their GraphQL projects.

Current folder structure:
.
├── index.ts
├── nodemon.json
├── package.json
├── package-lock.json
├── src
│   ├── config
│   │   └── db.ts
│   ├── models
│   │   └── user.model.ts
│   ├── resolvers
│   │   └── user.resolve.ts
│   └── types
│       ├── enums.ts
│       ├── inputs.ts
│       ├── interfaces.ts
│       ├── mutations.ts
│       ├── queries.ts
│       ├── scalars.ts
│       ├── types.ts
│       └── unions.ts
└── tsconfig.json

index.ts(root file):

import express from "express";
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { connectionDB } from "./src/config/db";
import { inputUser } from "./src/types/inputs";
import { interfaceResponse } from "./src/types/interfaces";
import { enumGender } from "./src/types/enums";
import { scalarDate } from "./src/types/scalars";
import { typeUser } from "./src/types/types";
import { typeQuery } from "./src/types/queries";
import { typeMutation } from "./src/types/mutations";
import { unionUser } from "./src/types/unions";
import { Mutation, Query } from "./src/resolvers/user.resolve";
import "dotenv/config";

const typeDefs = [interfaceResponse, inputUser, enumGender, scalarDate, typeUser, typeQuery, typeMutation, unionUser].join(" ");
const resolvers = { Query, Mutation };

const app = express();
const url = process.env.URL || "http://localhost:";
const port = Number(process.env.PORT) || 5000;
const server = new ApolloServer({
  typeDefs: typeDefs,
  resolvers: resolvers,
});

connectionDB();

startStandaloneServer(server, {
  listen: { port: port }
}).then((res) => {
  console.log(`Server running at ${res.url}`);
}).catch((err) => {
  console.log(err);
});

user.resolve.ts(resolver file):

import { GraphQLScalarType, Kind } from "graphql";
import { User } from "../models/user.model";

export const Query = {
    getAllUsers: async () => {
        const data = await User.find()
        return {
            code: "200",
            success: true,
            message: "Successfully fetched all users",
            data: data
        };
    },
    getUser: async (parent: any, { id }) => {
        const data = await User.findById({ _id: id });
        return {
            code: "200",
            success: true,
            message: "Successfully fetched user data",
            data: data
        };
    },
};

export const Mutation = {
    createNewUser: async (parent: any, { userData }) => {
        const data = await User.create(userData);
        return {
            code: "201",
            success: true,
            message: "Successfully created new user",
            data: data
        };
    },
    updateUser: async (parent: any, { id, userData }) => {
        const data = await User.findByIdAndUpdate({ _id: id }, { $set: userData }, { returnDocument: "after" });
        return {
            code: "200",
            success: true,
            message: "Successfully updated user",
            data: data
        };
    },
    deleteUser: async (parent: any, { id }) => {
        const data = await User.findByIdAndDelete({ _id: id });
        return {
            code: "200",
            success: true,
            message: "Successfully deleted user",
            data: data
        };
    },
};

types folder files(typeDef):

// types/enums.ts:
export const enumGender = "
    enum GENDER{
        male,
        female,
        other
    }
"

// types/inputs.ts:
export const inputUser = "
    input USER {
        username:String,
        email:String,
        phone:String,
        gender:GENDER
    }    
"

// types/interfaces.ts:
export const interfaceResponse = "
   interface Response{
    code : String!
    success : Boolean!
    message : String!
   }
"

// types/mutations.ts:
export const typeMutation = "
    type Mutation {
        createNewUser(userData:USER!): UserResponse
        updateUser(id: ID!,userData : USER): UserResponse
        deleteUser(id: ID!): UserResponse
    }
"

// types/queries.ts:
export const typeQuery = "
    type Query {
        getAllUsers: UsersResponse
        getUser(id: ID!): UserResponse
    }
"

// types/scalars.ts:
export const scalarDate =  "scalar Date"


// types/types.ts:
export const typeUser = "
    type User {
        id: ID!
        username: String!
        email: String!
        phone: String!
        gender: GENDER!
        createdAt: Date!
        updatedAt: Date!
    }

    type UsersResponse implements Response {
     code: String!
     success: Boolean!
     message: String!
     data: [User]
   }

    type UserResponse implements Response {
     code: String!
     success: Boolean!
     message: String!
     data: User
   }
"

// types/unions.ts:
export const unionUser = "union UserData = User"

My questions are:

  1. Folder Structure: How should I organize my project better for maintainability in the long run?

  2. Type Definitions: How can I improve the way I define GraphQL schemas (types, queries, mutations, etc.)?

  3. Resolvers: What are the best practices when defining resolvers in a separate file? Should I follow any specific pattern to make it more scalable?

  4. Combining Everything: Is there a better way to combine all the schemas and resolvers in the root file (index.ts) than joining them with .join(' ')?

  5. Best Practices: Any advice on improving my GraphQL project to align with industry standards or make it more professional?

Angular: Prevent BLUR event when CLICK event happens

I’m writing an Angular app where there is a scenario I’ve to prevent blur event when click event happens.
Problem is I’m not able to understand how this will happen as on click blur will always trigger since the target element is not in focus.

Is there any way I can achieve this? Below is a video of what is happening. You will notice that 1st the BLUR event is completed then the click event on click of Clear button.

issue blur/click

Here is a stackblitz example I’ve created.

is there any package to make a animation types like the videos? in js

I’m looking for a JavaScript or React.js library that can help me create an animation similar to the one in the video reference below:

Video link: Google Drive

I need to achieve a similar effect using JavaScript, preferably with a well-supported library like GSAP, Three.js, PixiJS, Anime.js, or any other suitable framework. If there’s a good way to implement this in React.js using hooks or Canvas, that would be helpful too.

Could someone recommend the best approach, tools, or frameworks for this? Any guidance, code snippets, or references would be greatly appreciated. Thanks in advance!

Multi-touch capability for web and mobile devices

Is there a way to register more than one finger and its position? In javascript there are options for reading cursor data and position. But it appears to have nothing for mobile devices and their ability to touch multiple places at once. Best i have found is reading the scroll position xyz. but that will at most allow you to read data about two fingers and not their actual locations. Also i am interested in trying to apply this to track pads for gestures, but i found the same thing. except for maybe an apple version which is supported by safari only.