Skip to content
This repository has been archived by the owner on Oct 18, 2024. It is now read-only.

Commit

Permalink
Merge pull request #581 from SuperViz/beta
Browse files Browse the repository at this point in the history
New version 🎉
  • Loading branch information
carlossantos74 authored Feb 26, 2024
2 parents d5b05bc + 00f573c commit 95043d5
Show file tree
Hide file tree
Showing 19 changed files with 316 additions and 351 deletions.
435 changes: 175 additions & 260 deletions src/services/realtime/ably/index.test.ts

Large diffs are not rendered by default.

81 changes: 45 additions & 36 deletions src/services/realtime/ably/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,44 +835,60 @@ export default class AblyRealtimeService extends RealtimeService implements Ably
* @description Finds an available slot index for the participant and confirms it.
* @returns {void}
*/
private findSlotIndex = (): void => {
let slots = new Array(16).fill(null).map((_, i) => ({ slotIndex: i, clientId: null }));
private findSlotIndex = async (): Promise<void> => {
const slot = Math.floor(Math.random() * 16);

this.supervizChannel.presence.get((error, presences) => {
if (error) {
slots = [];
return;
}
const hasAnyOneUsingMySlot = await new Promise((resolve) => {
this.supervizChannel.presence.get((error, presences) => {
if (error) {
resolve(true);
return;
}

presences.forEach((presence) => {
if (presence.clientId === this.myParticipant.clientId) return;
presences.forEach((presence) => {
if (presence.clientId === this.myParticipant.clientId) return;

if (presence.data.slotIndex !== undefined && presence.data.slotIndex !== null) {
slots[presence.data.slotIndex].clientId = presence.clientId;
}
if (presence.data.slotIndex === slot) resolve(true);
});

resolve(false);
});
});

const slotToUse = slots.find((slot) => slot.clientId === null);

if (!slotToUse) return;
if (hasAnyOneUsingMySlot) {
this.logger.log(
'slot already taken by someone else, trying again',
this.myParticipant.clientId,
);
this.findSlotIndex();
return;
}

this.myParticipant.data.slotIndex = slotToUse.slotIndex;
this.updateMyProperties({ slotIndex: slotToUse.slotIndex });
this.updateMyProperties({ slotIndex: slot });
};

private validateSlots() {
/**
* @function validateSlots
* @description Validates the slot index of all participants and resolves conflicts.
* @returns {void}
*/
private async validateSlots(): Promise<void> {
const slots = [];

this.supervizChannel.presence.get((_, presences) => {
presences.forEach((presence) => {
if (presence.data.slotIndex !== undefined && presence.data.slotIndex !== null) {
slots.push({
slotIndex: presence.data.slotIndex,
clientId: presence.clientId,
timestamp: presence.timestamp,
});
}
await new Promise((resolve) => {
this.supervizChannel.presence.get((_, presences) => {
presences.forEach((presence) => {
const hasValidSlot =
presence.data.slotIndex !== undefined && presence.data.slotIndex !== null;

if (hasValidSlot) {
slots.push({
slotIndex: presence.data.slotIndex,
clientId: presence.clientId,
timestamp: presence.timestamp,
});
}
});
resolve(true);
});
});

Expand All @@ -885,9 +901,7 @@ export default class AblyRealtimeService extends RealtimeService implements Ably
}[]
> = {};

slots.forEach((a, index) => {
if (slots.findIndex((b) => b.slotIndex === a.slotIndex) === index) return;

slots.forEach((a) => {
if (!duplicatesMap[a.slotIndex]) {
duplicatesMap[a.slotIndex] = [];
}
Expand All @@ -896,11 +910,6 @@ export default class AblyRealtimeService extends RealtimeService implements Ably
});

Object.values(duplicatesMap).forEach((arr) => {
if (arr.length === 1 && arr[0].clientId === this.myParticipant.clientId) {
this.findSlotIndex();
return;
}

const ordered = arr.sort((a, b) => a.timestamp - b.timestamp);
ordered.shift();

Expand Down
12 changes: 6 additions & 6 deletions src/services/video-conference-manager/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,12 @@ describe('VideoConferenceManager', () => {
test('should set callbacks if callbacks are defined', () => {
const callbacks = {
onToggleMicrophone: jest.fn(),
onToggleCamera: jest.fn(),
onToggleCam: jest.fn(),
onToggleTranscript: jest.fn(),
onToggleChat: jest.fn(),
onToggleScreenShare: jest.fn(),
onLeaveMeeting: jest.fn(),
onClickSettings: jest.fn(),
onClickHangup: jest.fn(),
onToggleMeetingSetup: jest.fn(),
};

VideoConferenceManagerInstance['onFrameLoad']();
Expand All @@ -303,12 +303,12 @@ describe('VideoConferenceManager', () => {
FrameEvent.FRAME_CALLBACKS_UPDATE,
JSON.stringify({
onToggleMicrophone: true,
onToggleCamera: true,
onToggleCam: true,
onToggleTranscript: true,
onToggleChat: true,
onToggleScreenShare: true,
onLeaveMeeting: true,
onClickSettings: true,
onClickHangup: true,
onToggleMeetingSetup: true,
}),
);
});
Expand Down
6 changes: 3 additions & 3 deletions src/services/video-conference-manager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,12 +321,12 @@ export default class VideoConfereceManager {

const callbacks = {
onToggleMicrophone: !!this.callbacks.onToggleMicrophone,
onToggleCamera: !!this.callbacks.onToggleCamera,
onToggleCam: !!this.callbacks.onToggleCam,
onToggleTranscript: !!this.callbacks.onToggleTranscript,
onToggleChat: !!this.callbacks.onToggleChat,
onToggleScreenShare: !!this.callbacks.onToggleScreenShare,
onLeaveMeeting: !!this.callbacks.onLeaveMeeting,
onClickSettings: !!this.callbacks.onClickSettings,
onClickHangup: !!this.callbacks.onClickHangup,
onToggleMeetingSetup: !!this.callbacks.onToggleMeetingSetup,
};

this.messageBridge.listen(MeetingControlsEvent.CALLBACK_CALLED, (callback: string) => {
Expand Down
6 changes: 3 additions & 3 deletions src/services/video-conference-manager/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ export interface VideoManagerOptions {
layoutMode?: LayoutMode;
callbacks?: {
onToggleMicrophone?: () => void;
onToggleCamera?: () => void;
onToggleCam?: () => void;
onToggleTranscript?: () => void;
onToggleChat?: () => void;
onToggleScreenShare?: () => void;
onLeaveMeeting?: () => void;
onClickSettings?: () => void;
onClickHangup?: () => void;
onToggleMeetingSetup?: () => void;
};
}

Expand Down
4 changes: 3 additions & 1 deletion src/web-components/base/styles/icon-button.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ export const iconButtonStyle = css`
.icon-button--clickable:hover:not(.icon-button--no-hover) {
background: rgb(var(--sv-gray-300));
transition: 0.25s background-color ease-in;
}
.icon-button--clickable:focus:not(.icon-button--no-hover) {
transition: 0.25s background-color ease-in;
background: rgb(var(--sv-gray-300));
}
`;
4 changes: 3 additions & 1 deletion src/web-components/comments/components/annotation-filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ export class CommentsAnnotationFilter extends WebComponentsBaseElement {
>
<div class="comments__filter__toggle-button" slot="dropdown">
<span class=${classMap(textClasses)}>${selectedLabel}</span>
<superviz-icon name=${this.caret} size="xs"></superviz-icon>
<div class="comments__filter__icon">
<superviz-icon name=${this.caret} size="xs"></superviz-icon>
</div>
</div>
</superviz-dropdown>
</div>
Expand Down
11 changes: 10 additions & 1 deletion src/web-components/comments/components/comment-input.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ describe('CommentsCommentInput', () => {

element['updateHeight']();

expect(textarea.style.height).toBe('41px');
expect(textarea.style.height).toBe('43px');
});

describe('addAtSymbolInCaretPosition', () => {
Expand Down Expand Up @@ -378,4 +378,13 @@ describe('CommentsCommentInput', () => {
expect(mockCancelComment).toHaveBeenCalled();
});
});

describe('focusInput', () => {
test('should focus keyboard cursor on input when clicking on it', () => {
element['getCommentInput']().focus = jest.fn();
element['focusInput']();

expect(element['getCommentInput']().focus).toHaveBeenCalled();
});
});
});
19 changes: 14 additions & 5 deletions src/web-components/comments/components/comment-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,12 @@ export class CommentsCommentInput extends WebComponentsBaseElement {
disconnectedCallback(): void {
super.disconnectedCallback();
if (!['create-annotation', 'create-comment'].includes(this.eventType)) return;
const textarea = this.getCommentInput();

this.removeEventListener('keyup', this.sendEnter);
const textarea = this.getCommentInput();
textarea.removeEventListener('keydown', this.sendEnter);
textarea.removeEventListener('click', this.focusInput);
textarea.addEventListener('input', this.handleInput);
}

protected firstUpdated(
Expand All @@ -115,9 +117,8 @@ export class CommentsCommentInput extends WebComponentsBaseElement {

if (commentTextarea) {
commentTextarea.addEventListener('input', this.handleInput);

const textarea = this.getCommentInput();
textarea.addEventListener('keydown', this.sendEnter);
commentTextarea.addEventListener('click', this.focusInput);
commentTextarea.addEventListener('keydown', this.sendEnter);
}

if (this.text.length > 0) {
Expand Down Expand Up @@ -171,6 +172,10 @@ export class CommentsCommentInput extends WebComponentsBaseElement {
return { searchText, position };
};

private focusInput = () => {
this.getCommentInput().focus();
};

private handleInput = (e: InputEvent) => {
if (this.commentInput?.value.length === 0) this.btnActive = false;
else this.btnActive = true;
Expand Down Expand Up @@ -249,6 +254,10 @@ export class CommentsCommentInput extends WebComponentsBaseElement {
}

private sendEnter = (e: KeyboardEvent) => {
if (e.key !== 'Escape') {
e.stopImmediatePropagation();
}

if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
}
Expand Down Expand Up @@ -419,7 +428,7 @@ export class CommentsCommentInput extends WebComponentsBaseElement {
></superviz-comments-mention-list>
<div class="sv-hr"></div>
<div class="comments__input__options">
<button class="icon-button comments__input__mention-button">
<button class="icon-button icon-button--medium icon-button--clickable">
<superviz-icon
name="mention"
@click=${this.addAtSymbolInCaretPosition}
Expand Down
2 changes: 1 addition & 1 deletion src/web-components/comments/components/comment-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export class CommentsCommentItem extends WebComponentsBaseElement {
<div class=${this.getClasses('header')}>
<div class=${this.getClasses('metadata')}>
${this.getAvatar()}
<span class="text text-bold sv-gray-600 ${this.getClasses('username')}"
<span class="text text-big text-bold sv-gray-700 ${this.getClasses('username')}"
>${this.username}</span
>
<span class="text text-small sv-gray-500 ${this.getClasses('date')}"
Expand Down
44 changes: 33 additions & 11 deletions src/web-components/comments/components/float-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,43 @@ export class CommentsFloatButton extends WebComponentsBaseElement {
if (!floatButton) return;

floatButton.setAttribute('style', this.positionStyles);

const windowSize = window.document.body.getBoundingClientRect().width;
const buttonPosition = floatButton.getBoundingClientRect();
const sideBarWidth = 320;

if (!this.commentsPosition || this.commentsPosition === 'left') {
this.shouldHide = buttonPosition.x < sideBarWidth;
return;
}

this.shouldHide = windowSize - buttonPosition.right < sideBarWidth;
});
}

private calculateIfShouldHide() {
const sidebar = document
.getElementsByTagName('superviz-comments')[0]
?.shadowRoot.querySelector('.superviz-comments');

const floatButton = this.shadowRoot.querySelector('.comments__floating-button');

if (!sidebar || !floatButton) return;

const {
left: sbLeft,
right: sbRight,
top: sbTop,
bottom: sbBottom,
} = sidebar.getBoundingClientRect();
const {
left: fbLeft,
right: fbRight,
top: fbTop,
bottom: fbBottom,
} = floatButton.getBoundingClientRect();

const sidebarHidesTop = sbBottom > fbTop && fbBottom > sbTop;
const sidebarHidesBottom = sbTop < fbBottom && fbTop < sbBottom;
const sidebarHidesLeft = sbRight > fbLeft && fbRight > sbLeft;
const sidebarHidesRight = sbLeft < fbRight && fbLeft < sbRight;

this.shouldHide =
(sidebarHidesBottom || sidebarHidesTop) && (sidebarHidesLeft || sidebarHidesRight);
}

protected render() {
this.calculateIfShouldHide();

const floatButtonClasses = {
'comments__floating-button': true,
'hide-button': !this.isHidden && this.shouldHide,
Expand Down
10 changes: 10 additions & 0 deletions src/web-components/comments/css/annotation-filter.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,14 @@ export const annotationFilterStyle = css`
align-items: center;
gap: 6px;
}
.comments__filter__toggle-button {
display: flex;
flex-direction: row;
gap: 4px;
}
.comments__filter__icon {
margin-top: -2px;
}
`;
14 changes: 1 addition & 13 deletions src/web-components/comments/css/comment-input.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const commentInputStyle = css`
white-space: pre-wrap;
word-wrap: break-word;
resize: none;
line-height: 1rem;
line-height: 1.15rem;
max-height: 5rem;
appearance: none;
height: 40px;
Expand Down Expand Up @@ -99,18 +99,6 @@ export const commentInputStyle = css`
visibility: visible;
}
.comments__input__mention-button {
display: flex;
align-items: center;
justify-content: center;
height: 32px;
width: 32px;
border-radius: 100%;
color: rgb(var(--sv-gray-600));
cursor: pointer;
transition: 0.25s background-color ease-in;
}
.mention:hover {
background-color: rgb(var(--sv-gray-200));
}
Expand Down
4 changes: 0 additions & 4 deletions src/web-components/comments/css/comment-item.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,4 @@ export const commentItemStyle = css`
.mentioned {
display: inline-block;
}
.comments__comment-item__username {
font-size: 14px;
}
`;
Loading

0 comments on commit 95043d5

Please sign in to comment.