Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@internxt/css-config": "^1.0.2",
"@internxt/eslint-config-internxt": "^2.0.0",
"@internxt/lib": "^1.2.0",
"@internxt/sdk": "=1.11.8",
"@internxt/sdk": "=1.11.9",
"@internxt/ui": "0.0.25",
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.17/jitsi-excalidraw-0.0.17.tgz",
"@jitsi/js-utils": "2.2.1",
Expand Down
7 changes: 7 additions & 0 deletions react/features/base/connection/actions.any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '../util/uri';

import { setJoinRoomError } from "../meet/general/store/errors/actions";
import { LocalStorageManager } from "../meet/LocalStorageManager";
import MeetingService from "../meet/services/meeting.service";
import {
CONNECTION_DISCONNECTED,
Expand Down Expand Up @@ -238,10 +239,16 @@ export function _connectInternal({

if (room !== NEW_MEETING_URL)
try {
let userUUID: string | undefined;

if (isAnonymous) {
userUUID = LocalStorageManager.instance.getOrCreateAnonymousUUID();
}
const { token: jwt, appId } = await MeetingService.instance.joinCall(room, {
name: displayName ?? name ?? "",
lastname: lastname ?? "",
anonymous: !!isAnonymous,
anonymousId: userUUID,
});

const newOptions = get8x8Options(options, appId, room);
Expand Down
10 changes: 6 additions & 4 deletions react/features/base/connection/actions.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { stopLocalVideoRecording } from '../../recording/actions.any';
import LocalRecordingManager from '../../recording/components/Recording/LocalRecordingManager.web';
import { setJWT } from '../jwt/actions';

import { LocalStorageManager } from "../meet/LocalStorageManager";
import MeetingService from "../meet/services/meeting.service";
import { _connectInternal } from "./actions.any";

Expand All @@ -27,8 +28,9 @@ export function connect(id?: string, password?: string) {
const state = getState();
const { jwt } = state["features/base/jwt"];
const { iAmRecorder, iAmSipGateway } = state["features/base/config"];
const { user } = state["features/user"];

// TODO: CHECK WHY USER REDUCER IS NULL IN THIS POINT, initializers are not executing as expected
// const { user } = state["features/user"];
const user = LocalStorageManager.instance.getUser();
if (!iAmRecorder && !iAmSipGateway && isVpaasMeeting(state)) {
return dispatch(getCustomerDetails())
.then(() => {
Expand All @@ -44,7 +46,7 @@ export function connect(id?: string, password?: string) {
password,
name: user?.name,
lastname: user?.lastname,
isAnonymous: !!user,
isAnonymous: !user,
})
)
);
Expand All @@ -67,7 +69,7 @@ export function connect(id?: string, password?: string) {
password,
name: user?.name,
lastname: user?.lastname,
isAnonymous: !!user,
isAnonymous: !user,
})
);
};
Expand Down
43 changes: 41 additions & 2 deletions react/features/base/meet/LocalStorageManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { UserSubscription } from "@internxt/sdk/dist/drive/payments/types/types";
import { v4 } from "uuid";
import { User } from "./general/store/user/types";

/**
Expand All @@ -19,6 +20,7 @@ export class LocalStorageManager {
MNEMONIC: "xMnemonic",
USER: "xUser",
SUBSCRIPTION: "xSubscription",
ANONYMOUS_USER_UUID: "xAnonymousUserUUID",
};

private constructor() {}
Expand Down Expand Up @@ -152,8 +154,8 @@ export class LocalStorageManager {
/**
* Gets the user information
*/
public getUser<T = any>(): T | null | undefined {
return this.get<T>(LocalStorageManager.KEYS.USER);
public getUser(): User | null | undefined {
return this.get(LocalStorageManager.KEYS.USER);
}

/**
Expand Down Expand Up @@ -184,6 +186,42 @@ export class LocalStorageManager {
this.remove(LocalStorageManager.KEYS.SUBSCRIPTION);
}

/**
* Generates and stores a UUID for anonymous users
* @returns The generated or existing UUID
*/
public getOrCreateAnonymousUUID(): string {
let uuid = this.get<string>(LocalStorageManager.KEYS.ANONYMOUS_USER_UUID);

if (!uuid) {
uuid = v4();
this.set(LocalStorageManager.KEYS.ANONYMOUS_USER_UUID, uuid);
}

return uuid;
}

/**
* Gets the anonymous user UUID
*/
public getAnonymousUUID(): string | null | undefined {
return this.get<string>(LocalStorageManager.KEYS.ANONYMOUS_USER_UUID);
}

/**
* Sets the anonymous user UUID
*/
public setAnonymousUUID(uuid: string): void {
this.set(LocalStorageManager.KEYS.ANONYMOUS_USER_UUID, uuid);
}

/**
* Removes the anonymous user UUID
*/
public removeAnonymousUUID(): void {
this.remove(LocalStorageManager.KEYS.ANONYMOUS_USER_UUID);
}

/**
* Saves the session credentials
* @param token Token
Expand Down Expand Up @@ -218,6 +256,7 @@ export class LocalStorageManager {
this.remove(LocalStorageManager.KEYS.MNEMONIC);
this.remove(LocalStorageManager.KEYS.USER);
this.remove(LocalStorageManager.KEYS.SUBSCRIPTION);
this.remove(LocalStorageManager.KEYS.ANONYMOUS_USER_UUID);
}

public clearStorage(): void {
Expand Down
2 changes: 1 addition & 1 deletion react/features/base/meet/general/store/user/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function clearUser(): {
export const initializeUser = (): ThunkAction<void, IReduxState, unknown, AnyAction> => {
return (dispatch) => {
const localStorageManager = LocalStorageManager.instance;
const user = localStorageManager.getUser<User>();
const user = localStorageManager.getUser();

if (user) {
dispatch(setUser(user));
Expand Down
5 changes: 2 additions & 3 deletions react/features/base/meet/middlewares/meeting.middleware.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { UserSettings } from "@internxt/sdk/dist/shared/types/userSettings";
import { AnyAction, Dispatch, Middleware } from "redux";

import MiddlewareRegistry from "../../redux/MiddlewareRegistry";
Expand Down Expand Up @@ -131,7 +130,7 @@ export const refreshUserData = async (dispatch: Dispatch<AnyAction>, force: bool
const now = Date.now();
const lastRefreshTime = LocalStorageManager.instance.get<number>(STORAGE_KEYS.LAST_USER_REFRESH, 0) ?? 0;
const hasExpiredRefreshInterval = now - lastRefreshTime > USER_REFRESH_INTERVAL;
const currentUser = LocalStorageManager.instance.getUser<UserSettings>();
const currentUser = LocalStorageManager.instance.getUser();
const tokenNeedsRefresh = shouldRefreshToken();

if (!currentUser) {
Expand Down Expand Up @@ -193,7 +192,7 @@ const shouldRefreshToken = (): boolean => {
*/
export const refreshUserAvatar = async (dispatch: Dispatch<AnyAction>): Promise<void> => {
try {
const currentUser = LocalStorageManager.instance.getUser<UserSettings>();
const currentUser = LocalStorageManager.instance.getUser();
if (!currentUser?.avatar) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useMemo } from "react";
import React from "react";
import { WithTranslation } from "react-i18next";
import { connect, useSelector } from "react-redux";
import { IReduxState } from "../../../../../app/types";
Expand All @@ -7,8 +7,7 @@ import { getCurrentConference } from "../../../../conference/functions";
import { translate } from "../../../../i18n/functions";
import { useAspectRatio } from "../../../general/hooks/useAspectRatio";
import { useE2EEActivation } from "../../../general/hooks/useE2EEActivation";
import MeetingService from "../../../services/meeting.service";
import { MeetingUser } from "../../../services/types/meeting.types";
import { useParticipantAvatar } from "../../PreMeeting/hooks/useParticipantAvatar";
import VideoGallery from "../components/VideoGallery";
import VideoSpeaker from "../components/VideoSpeaker";
import { getParticipantsWithTracks } from "../utils";
Expand All @@ -28,52 +27,20 @@ const GalleryVideoWrapper = ({ videoMode, t, isE2EESupported, room }: GalleryVid
const { containerStyle } = useAspectRatio();
useE2EEActivation(isE2EESupported);

const participants = useSelector((state: IReduxState) => getParticipantsWithTracks(state));
useParticipantAvatar();
const participants = useSelector(getParticipantsWithTracks);
const flipX = useSelector((state: IReduxState) => state["features/base/settings"].localFlipX);

const contStyle = videoMode === "gallery" ? containerStyle : {};
const [meetingParticipants, setMeetingParticipants] = React.useState<MeetingUser[]>([]);

useEffect(() => {
const fetchMeetingParticipants = async (): Promise<void> => {
if (!room) return;

try {
const meetingParticipantsData = await MeetingService.instance.getCurrentUsersInCall(room);
setMeetingParticipants(meetingParticipantsData);
} catch (error) {
console.error("Error fetching meeting participants:", error);
}
};

fetchMeetingParticipants();
}, [room, participants?.length]);

const participantsWithAvatar = useMemo(() => {
if (!participants || participants.length === 0) return [];
if (!meetingParticipants || meetingParticipants.length === 0) return participants;

const avatarMap: Record<string, string | undefined> = {};
meetingParticipants.forEach((mp) => {
if (mp.userId) {
avatarMap[mp.userId] = mp.avatar;
}
});

return participants.map((participant) => ({
...participant,
avatarSource: avatarMap[participant.id],
}));
}, [participants, meetingParticipants]);

return (
<div className="h-full w-full bg-gray-950" style={contStyle}>
<AudioTracksContainer />
<div className={videoMode === "gallery" ? "block" : "hidden"}>
<VideoGallery participants={participantsWithAvatar} translate={t} flipX={flipX} />
<VideoGallery participants={participants} translate={t} flipX={flipX} />
</div>
<div className={videoMode === "speaker" ? "block" : "hidden"}>
<VideoSpeaker participants={participantsWithAvatar} translate={t} flipX={flipX} />
<VideoSpeaker participants={participants} translate={t} flipX={flipX} />
</div>
</div>
);
Expand All @@ -87,7 +54,7 @@ function mapStateToProps(state: IReduxState, ownProps: OwnProps): MappedStatePro
return {
...ownProps,
isE2EESupported,
room
room,
};
}

Expand Down
1 change: 1 addition & 0 deletions react/features/base/meet/views/Conference/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const getParticipantsWithTracks = (state: IReduxState) => {
hidden: false,
dominantSpeaker: participant.dominantSpeaker || false,
raisedHand: hasRaisedHand(participant),
avatarSource: !!participant.loadableAvatarUrl ? participant.loadableAvatarUrl : participant.avatarURL,
};
})
.filter((participant) => !participant.hidden);
Expand Down
32 changes: 21 additions & 11 deletions react/features/base/meet/views/PreMeeting/PreMeetingScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ import { updateSettings } from "../../../settings/actions";
import { getDisplayName } from "../../../settings/functions.web";
import { withPixelLineHeight } from "../../../styles/functions.web";
import MeetingButton from "../../general/containers/MeetingButton";
import { logout } from "../../general/store/auth/actions";
import { loginSuccess, logout } from "../../general/store/auth/actions";
import { setCreateRoomError } from "../../general/store/errors/actions";
import { useLocalStorage } from "../../LocalStorageManager";
import MeetingService from "../../services/meeting.service";
import { MeetingUser } from "../../services/types/meeting.types";
import AuthModal from "../Home/containers/AuthModal";
import Header from "./components/Header";
import PreMeetingModal from "./components/PreMeetingModal";
import SecureMeetingMessage from "./components/SecureMeetingMessage";
Expand Down Expand Up @@ -202,6 +203,9 @@ const PreMeetingScreen = ({
const [isCreatingMeeting, setIsCreatingMeeting] = useState(false);
const [meetingUsersData, setMeetingUsersData] = useState<MeetingUser[]>([]);
const userData = useUserData();
const [openLogin, setOpenLogin] = useState<boolean>(true);

const [isAuthModalOpen, setIsAuthModalOpen] = useState<boolean>(false);

const storageManager = useLocalStorage();
const dispatch = useDispatch();
Expand Down Expand Up @@ -271,11 +275,6 @@ const PreMeetingScreen = ({
}
};

const handleRedirectToSignUp = () => {
// HARDCODED, MODIFY WHEN SIGN UP PAGE IS READY
window.location.href = "https://drive.internxt.com/new";
};

const updateNameInStorage = (name: string) => {
try {
const user = storageManager.getUser();
Expand Down Expand Up @@ -318,9 +317,15 @@ const PreMeetingScreen = ({
userData={userData}
subscription={subscription}
translate={t}
onLogin={handleRedirectToLogin}
onLogin={() => {
setOpenLogin(true);
setIsAuthModalOpen(true);
}}
onSignUp={() => {
setOpenLogin(false);
setIsAuthModalOpen(true);
}}
onLogout={onLogout}
onSignUp={handleRedirectToSignUp}
meetingButton={
isInNewMeeting ? (
<MeetingButton
Expand Down Expand Up @@ -352,12 +357,17 @@ const PreMeetingScreen = ({
isCreatingConference={!!createConference}
errorMessage={errorMessage}
/>

<div className="flex absolute bottom-7 right-7">{isE2EESupported && <SecureMeetingMessage />}</div>
<AuthModal
isOpen={isAuthModalOpen}
openLogin={openLogin}
onClose={() => setIsAuthModalOpen(false)}
onSignup={(credentials) => dispatch(loginSuccess(credentials))}
translate={t}
/>
;<div className="flex absolute bottom-7 right-7"><SecureMeetingMessage /></div>
<div className={classes.videoEncodingToggleContainer}>
<VideoEncodingToggle />
</div>

{/* UNCOMMENT IN DEV MODE TO SEE OLD IMPLEMENTATION */}
{/* <div className="flex flex-row">
<div>
Expand Down
Loading
Loading