Parameters of a function wrongly transmitted to firebase functions

exports.createUserProfileManual = functions.https.onCall(async (
    data, context) => {
  // Validate the data
  const {uid, email} = data;
  if (!uid || !email) {
    throw new functions.https.HttpsError("invalid-argument",
        "Missing UID or email.");
  }
  const userProfile = {
    uid,
    email,
    createdAt: admin.firestore.FieldValue.serverTimestamp(),
  };

  try {
    await firestore.collection("users").doc(uid).set(userProfile);
    console.log(`User profile created for UID: ${uid}`);
    return {message: "User profile created successfully"};
  } catch (error) {
    console.error("Error creating user profile:", error);
    throw new functions.https.HttpsError("internal", error.message);
  }
});

This is my firebase function, and where it is used:

`document.getElementById("register-form").addEventListener("submit", async (e) => {
    e.preventDefault();
    const email = document.getElementById("register-email").value.trim();
    const password = document.getElementById("register-password").value.trim();
    
    if (!email || !password) {
      alert("Please provide both email and password.");
      return;
    }
    
    try {
      // Create user in Firebase Authentication
      const userCredential = await createUserWithEmailAndPassword(auth, email, password);
      const user = userCredential.user;
      console.log("User successfully created:", user.uid);
  
      // Call the callable cloud function to create the user profile
      const createUserProfile = httpsCallable(functions, "createUserProfileManual");
      const result = await createUserProfile({ uid: user.uid, email: user.email });
      console.log("Cloud Function result:", result.data);
  
      alert("User registration and profile creation successful!");
    } catch (error) {
      console.error("Registration Error:", error);
      alert(`Error: ${error.message}`);
    }
  });`
  

Online I got this https error: Error: Missing UID or email.
which seems to indicate that parameters aren’t passed properly to the function.
What is weird is that in my functions log in the console, I can see the data transmitted being correct.

I first tried to put the auth and creation both in the functions which didn’t work, the function I tried also to put the parameters as not mandatory and I correctly created a document in my firestore but of course without email.

document.querySelector null error in Safari [closed]

My component layout:

/components/navigation/footer.js
/components/A/index.js

Within index.js I have:

const bottomnavtarget = document.querySelector(".MuiBottomNavigation-root");

and then on form change:

onChange={()=>(bottomnavtarget.classList.add('cf'))}

So when the form changes, I am trying to add a class to MuiBottomNavigation-root (which is within footer.js)

This works OK on Chrome, but in Safari I get the error:

TypeError: null is not an object (evaluating 'bottomnavtarget.classList')

How can I access this class for when the form changes?

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

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.

Tampermonkey script email disappearing

I have this script for tampermonkey that should enter a random email on Spotify sign up page and click on submit. For now it does enter the email but it disappears after 2 secs instead of staying in the placeholder, it gives an “This email is invalid. Make sure it’s written like [email protected]” as it’s empty and it doesn’t click on submit.

// ==UserScript==
// @name         Spotify Auto Registration
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Automate Spotify account creation
// @author       You
// @match        https://*.spotify.com/*/signup*
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function () {
    'use strict';

    // Helper function to generate a valid random email with only letters
    function generateRandomEmail() {
        const letters = 'abcdefghijklmnopqrstuvwxyz';
        let randomString = '';
        for (let i = 0; i < 8; i++) { // Generate an 8-character string
            randomString += letters[Math.floor(Math.random() * letters.length)];
        }
        const domains = ['gmail.com', 'yahoo.com', 'outlook.com'];
        const randomDomain = domains[Math.floor(Math.random() * domains.length)];
        return `${randomString}@${randomDomain}`;
    }

    // Helper function for wait time
    function wait(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    // Function to fill out the form
    async function fillSpotifyForm() {
        const email = GM_getValue('lastEmail', generateRandomEmail()); // Get or generate email
        const password = 'Spotify123!'; // Replace with your desired password

        console.log(`Creating account with email: ${email}`);

        try {
            // Fill email field
            const emailInputField = document.querySelector('#username');
            if (emailInputField) {
                emailInputField.focus();
                emailInputField.value = email;
                await wait(500); // Allow the field to process input
            }

            // Click the next button
            const submitButton = document.querySelector('button[data-testid="submit"]');
            if (submitButton && !submitButton.disabled) {
                submitButton.click();
                await wait(1000); // Wait for the next step to load
            }

            
        } catch (error) {
            console.error('Error filling the form:', error);
        }
    }

    // Wait for the page to load and execute the script
    window.addEventListener('load', () => {
        setTimeout(() => {
            fillSpotifyForm();
        }, 2000); // Adjust delay as needed
    });
})();