Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

createRoomContext is not a function #4

Open
rafiqulshopon opened this issue Feb 6, 2024 · 2 comments
Open

createRoomContext is not a function #4

rafiqulshopon opened this issue Feb 6, 2024 · 2 comments

Comments

@rafiqulshopon
Copy link

rafiqulshopon commented Feb 6, 2024

I'm getting this error -

image

my liveblocks.config.ts code -

import { LiveMap, createClient } from '@liveblocks/client';
import { createRoomContext } from '@liveblocks/react';

const client = createClient({
  throttle: 16,
  publicApiKey: process.env.NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY!,
});

// Presence represents the properties that exist on every user in the Room
// and that will automatically be kept in sync. Accessible through the
// `user.presence` property. Must be JSON-serializable.
type Presence = {
  // cursor: { x: number, y: number } | null,
  // ...
};

// Optionally, Storage represents the shared document that persists in the
// Room, even after all users leave. Fields under Storage typically are
// LiveList, LiveMap, LiveObject instances, for which updates are
// automatically persisted and synced to all connected clients.
type Storage = {
  // author: LiveObject<{ firstName: string, lastName: string }>,
  // ...
  canvasObjects: LiveMap<string, any>;
};

// Optionally, UserMeta represents static/readonly metadata on each user, as
// provided by your own custom auth back end (if used). Useful for data that
// will not change during a session, like a user's name or avatar.
type UserMeta = {
  // id?: string,  // Accessible through `user.id`
  // info?: Json,  // Accessible through `user.info`
};

// Optionally, the type of custom events broadcast and listened to in this
// room. Use a union for multiple events. Must be JSON-serializable.
type RoomEvent = {
  // type: "NOTIFICATION",
  // ...
};

// Optionally, when using Comments, ThreadMetadata represents metadata on
// each thread. Can only contain booleans, strings, and numbers.
export type ThreadMetadata = {
  resolved: boolean;
  zIndex: number;
  time?: number;
  x: number;
  y: number;
};

export const {
  suspense: {
    RoomProvider,
    useRoom,
    useMyPresence,
    useUpdateMyPresence,
    useSelf,
    useOthers,
    useOthersMapped,
    useOthersConnectionIds,
    useOther,
    useBroadcastEvent,
    useEventListener,
    useErrorListener,
    useStorage,
    useObject,
    useMap,
    useList,
    useBatch,
    useHistory,
    useUndo,
    useRedo,
    useCanUndo,
    useCanRedo,
    useMutation,
    useStatus,
    useLostConnectionListener,
    useThreads,
    useUser,
    useCreateThread,
    useEditThreadMetadata,
    useCreateComment,
    useEditComment,
    useDeleteComment,
    useAddReaction,
    useRemoveReaction,
  },
} = createRoomContext<Presence, Storage, UserMeta, RoomEvent, ThreadMetadata>(
  client,
  {
    async resolveUsers({ userIds }) {
      // Used only for Comments. Return a list of user information retrieved
      // from `userIds`. This info is used in comments, mentions etc.

      // const usersData = await __fetchUsersFromDB__(userIds);
      //
      // return usersData.map((userData) => ({
      //   name: userData.name,
      //   avatar: userData.avatar.src,
      // }));

      return [];
    },
    async resolveMentionSuggestions({ text, roomId }) {
      // Used only for Comments. Return a list of userIds that match `text`.
      // These userIds are used to create a mention list when typing in the
      // composer.
      //
      // For example when you type "@jo", `text` will be `"jo"`, and
      // you should to return an array with John and Joanna's userIds:
      // ["[email protected]", "[email protected]"]

      // const userIds = await __fetchAllUserIdsFromDB__(roomId);
      //
      // Return all userIds if no `text`
      // if (!text) {
      //   return userIds;
      // }
      //
      // Otherwise, filter userIds for the search `text` and return
      // return userIds.filter((userId) =>
      //   userId.toLowerCase().includes(text.toLowerCase())
      // );

      return [];
    },
  }
);

my repo - https://github.com/rafiqulshopon/figma-clone

@adrianhajdin Could you please help me to solve this issue.

@lvntruong
Copy link

Hi @rafiqulshopon
I think this issue relative to this #16 (comment)
Thanks!

@ridsb
Copy link

ridsb commented Dec 31, 2024

Hi @rafiqulshopon I faced the same error. This is because code places resolveUsers and resolveMentionSuggestions in an unsupported location (createRoomContext), which causes them to not work as intended.This functions are not supported in the createRoomContext method. They must be defined at the createClient level.

The code below will solve the error.

import { LiveMap, createClient } from "@liveblocks/client";
import { createRoomContext } from "@liveblocks/react";

// Initialize Liveblocks client with your public API key and additional configurations
const client = createClient({
  throttle: 16,
  publicApiKey: process.env.NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY!,
  // Move resolveUsers to createClient
  async resolveUsers({ userIds }) {
    // Fetch user data from an external source (example, from a database)
    const usersData = await fetchUsersFromDatabase(userIds);
    
    // Map each user data to return name and avatar (assuming avatar is a URL or string)
    return usersData.map((userData) => ({
      name: userData.name,
      avatar: userData.avatar, // If avatar is a string (URL), use it directly
    }));
  },

  // Resolve mention suggestions for comments based on text input
  async resolveMentionSuggestions({ text, roomId }) {
    // Fetch user IDs from your database (example)
    const userIds = await fetchAllUserIdsFromDB(roomId);

    // If no text is provided, return all user IDs
    if (!text) {
      return userIds;
    }

    // Otherwise, filter user IDs based on the search `text`
    return userIds.filter((userId) =>
      userId.toLowerCase().includes(text.toLowerCase())
    );
  },
});

// Define the types for the presence, storage, user metadata, room events, and thread metadata

// Presence represents the properties that exist on every user in the Room
type Presence = {
  // Example: cursor tracking (uncomment and update as needed)
  // cursor: { x: number, y: number } | null,
};

// Storage represents the shared document that persists in the Room
type Storage = {
  // Example: canvas objects in LiveMap
  canvasObjects: LiveMap<string, any>;
};

// UserMeta represents static/readonly metadata for each user
type UserMeta = {
  // Example: user ID or other static info
  // id?: string,  // Accessible through `user.id`
  // info?: Json,  // Accessible through `user.info`
};

// RoomEvent represents custom events broadcast and listened to in the room
type RoomEvent = {
  // Example: custom event type
  // type: "NOTIFICATION",
};

// ThreadMetadata represents metadata on each thread (for comments)
export type ThreadMetadata = {
  resolved: boolean;
  zIndex: number;
  time?: number;
  x: number;
  y: number;
};

// Create the room context with the necessary types and configuration
export const {
  suspense: {
    RoomProvider,
    useRoom,
    useMyPresence,
    useUpdateMyPresence,
    useSelf,
    useOthers,
    useOthersMapped,
    useOthersConnectionIds,
    useOther,
    useBroadcastEvent,
    useEventListener,
    useErrorListener,
    useStorage,
    useObject,
    useMap,
    useList,
    useBatch,
    useHistory,
    useUndo,
    useRedo,
    useCanUndo,
    useCanRedo,
    useMutation,
    useStatus,
    useLostConnectionListener,
    useThreads,
    useUser,
    useCreateThread,
    useEditThreadMetadata,
    useCreateComment,
    useEditComment,
    useDeleteComment,
    useAddReaction,
    useRemoveReaction,
  },
} = createRoomContext<Presence, Storage, UserMeta, RoomEvent, ThreadMetadata>(client);

// Example function to simulate fetching user data from a database or external source
async function fetchUsersFromDatabase(userIds: string[]) {
  // Placeholder example - in a real scenario, replace with actual DB/API call
  return userIds.map((userId) => ({
    name: `User ${userId}`,
    avatar: `https://example.com/avatars/${userId}.jpg`, // Example avatar URL
  }));
}

// Example function to simulate fetching all user IDs for a room from the database
async function fetchAllUserIdsFromDB(roomId: string) {
  // Placeholder example - in a real scenario, replace with actual DB/API call
  return ["user1", "user2", "user3"];
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants