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

Add Timezone sharing #810

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open
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
66 changes: 66 additions & 0 deletions src/app/molecules/room-timezone/RoomTimezone.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';

import initMatrix from '../../../client/initMatrix';
import Button from '../../atoms/button/Button';
import Text from '../../atoms/text/Text';

import './RoomTimezone.scss';

function RoomTimezone({ roomId }) {
const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId);
const userId = mx.getUserId();

const timezoneEventId = room.currentState.getStateEvents('in.cinny.shared_timezone', userId)?.event?.content?.user_timezone_event;
const timezoneEvent = room.findEventById(timezoneEventId);
const timezoneContent = timezoneEvent?.getContent();

const [timezone, setTimezone] = useState(timezoneContent?.user_timezone);

const clearTimezone = () => {
const eventKey = room.currentState.getStateEvents('in.cinny.shared_timezone', userId)?.event?.content?.user_timezone_event;
mx.redactEvent(roomId, eventKey);
mx.sendStateEvent(roomId, 'in.cinny.shared_timezone', { }, userId);
setTimezone(null);
};

const shareTimezone = () => {
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
setTimezone(userTimezone);
const content = {
user_timezone: userTimezone,
msgtype: 'in.cinny.share_timezone',
};
mx.sendEvent(roomId, 'in.cinny.share_timezone', content).then((event) => {
// Append the shared timezone event to the room state
mx.sendStateEvent(roomId, 'in.cinny.shared_timezone', { user_timezone_event: event.event_id }, userId);
});
};

return (
<div className="room-timezone__content">
<Text className="room-timezone__message">Share your timezone</Text>
<Text className="room-timezone__message" variant="b3">
Sharing your timezone will allow other users in this room to see your local time.
Keep in mind that sharing your timezone will share your approximate location.
</Text>
<Text className="room-timezone__message" variant="b2">
{timezone ? `Currently shared timezone: ${timezone}` : 'You are not currently sharing a timezone'}
</Text>
<Button onClick={() => shareTimezone()} variant={timezone ? 'surface' : 'danger'}>
{timezone ? 'Update Timezone' : 'Share Timezone'}
</Button>

<Button onClick={() => clearTimezone()} disabled={!timezone}>
Clear Shared Timezone
</Button>
</div>
);
}

RoomTimezone.propTypes = {
roomId: PropTypes.string.isRequired,
};

export default RoomTimezone;
84 changes: 84 additions & 0 deletions src/app/molecules/room-timezone/RoomTimezone.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@use '../../partials/flex';
@use '../../partials/dir';
@use '../../partials/text';

.room-timezone {
&__message,
& .setting-tile {
margin: var(--sp-tight) var(--sp-normal);
}
& .setting-tile {
margin-bottom: var(--sp-loose);
}

&__alias-item {
padding: var(--sp-extra-tight) var(--sp-normal);
@extend .cp-fx__row--s-c;
&.checkbox {
@include dir.side(margin, 0 , var(--sp-tight));
}
& .text {
@extend .cp-fx__item-one;
@extend .cp-txt__ellipsis;
color: var(--tc-surface-high);
span {
margin: 0 var(--sp-extra-tight);
padding: 0 var(--sp-ultra-tight);
color: var(--bg-surface);
background-color: var(--tc-surface-low);
border-radius: 4px;
}
}
}
&__item-btns {
@include dir.side(margin, 48px, 0);
& button {
padding: var(--sp-ultra-tight) var(--sp-tight);
margin-bottom: var(--sp-tight);
@include dir.side(margin, 0, var(--sp-tight));
}
}

&__content {
margin-bottom: var(--sp-normal);

& .checkbox {
@include dir.side(margin, 0, var(--sp-tight));
min-width: 20px;
}
& > button {
margin: 0 var(--sp-normal);
}
}

&__form {
padding: var(--sp-normal);
padding-top: 0;
display: flex;
&-label {
padding: var(--sp-normal) var(--sp-normal) var(--sp-ultra-tight);
}
}

&__input-wrapper {
display: flex;
@extend .cp-fx__item-one;
@include dir.side(margin, 0, var(--sp-tight));

& .input-container {
@extend .cp-fx__item-one;
}
}

&__input-status {
padding: 0 var(--sp-normal);
}
&__valid {
color: var(--tc-positive-high);
padding-bottom: var(--sp-normal);
}
&__invalid {
color: var(--tc-danger-high);
padding-bottom: var(--sp-normal);
}
}
89 changes: 89 additions & 0 deletions src/app/organisms/room/RoomBanner.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';

import initMatrix from '../../../client/initMatrix';
import Text from '../../atoms/text/Text';

import './RoomBanner.scss';
import RawIcon from '../../atoms/system-icons/RawIcon';

import RecentClockIC from '../../../../public/res/ic/outlined/recent-clock.svg';

import { twemojify } from '../../../util/twemojify';
import { getUsernameOfRoomMember } from '../../../util/matrixUtil';

function RoomBanner({ roomId }) {
const mx = initMatrix.matrixClient;
const isDM = initMatrix.roomList.directs.has(roomId);
const room = mx.getRoom(roomId);

const [time, setTime] = useState(null);

let partner = null;

if (isDM) {
partner = room.getAvatarFallbackMember();
}

const timezoneEventId = room.currentState.getStateEvents('in.cinny.shared_timezone', partner?.userId)?.event?.content?.user_timezone_event;
const timezoneEvent = room.findEventById(timezoneEventId);

let timezoneContent = null;

const updateTime = () => {
if (isDM) {
const timezone = timezoneContent?.user_timezone;
const date = new Date();

try {
const partnerLocalTime = date.toLocaleTimeString([], { timeZone: timezone, hour: '2-digit', minute: '2-digit' });
const userTime = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
// if the partner time and user time are the same, we wont show the time
if (userTime !== partnerLocalTime) { setTime(`${getUsernameOfRoomMember(partner)}'s local time is: ${partnerLocalTime}`); }
} catch {
setTime(null);
}
}
};

if (timezoneEvent) {
if (!timezoneEvent.getClearContent()) {
timezoneEvent.attemptDecryption(mx.crypto);
}

timezoneContent = timezoneEvent.getContent();
timezoneEvent.getDecryptionPromise()?.then(() => {
timezoneContent = timezoneEvent.getContent();
updateTime();
});
}

useEffect(() => {
updateTime();
const interval = setInterval(() => updateTime(), 20000);
return () => {
setTime(null);
clearInterval(interval);
};
}, [room]);

return (
<div>
{ time ? (
<div className="room-view__banner">
<RawIcon src={RecentClockIC} size="small" />
<Text>
{ twemojify(time) }
</Text>
</div>
)
: null }
</div>
);
}

RoomBanner.propTypes = {
roomId: PropTypes.string.isRequired,
};

export default RoomBanner;
28 changes: 28 additions & 0 deletions src/app/organisms/room/RoomBanner.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@use '../../partials/flex';
@use '../../partials/text';
@use '../../partials/dir';

.room-view {
&__banner {
background-color: var(--bg-surface-low);
width: calc(100% - var(--sp-extra-loose));

padding: var(--sp-ultra-tight);
border-radius: var(--bo-radius);
align-items: center;

position: relative;
@include dir.prop(left, var(--sp-normal), unset);
@include dir.prop(right, unset, var(--sp-normal));
display: flex;
z-index: 999;
transform: translate(0%, 10%);
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 20%);

& .ic-raw {
opacity: 0.4;
margin: 0 var(--sp-extra-tight);
}

}
}
5 changes: 5 additions & 0 deletions src/app/organisms/room/RoomSettings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import ChevronTopIC from '../../../../public/res/ic/outlined/chevron-top.svg';

import { useForceUpdate } from '../../hooks/useForceUpdate';
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
import RoomTimezone from '../../molecules/room-timezone/RoomTimezone';

const tabText = {
GENERAL: 'General',
Expand Down Expand Up @@ -120,6 +121,10 @@ function GeneralSettings({ roomId }) {
<MenuHeader>Room addresses</MenuHeader>
<RoomAliases roomId={roomId} />
</div>
<div className="room-settings__card">
<MenuHeader>Timezones</MenuHeader>
<RoomTimezone roomId={roomId} />
</div>
</>
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/app/organisms/room/RoomView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import RoomViewContent from './RoomViewContent';
import RoomViewFloating from './RoomViewFloating';
import RoomViewInput from './RoomViewInput';
import RoomViewCmdBar from './RoomViewCmdBar';
import RoomBanner from './RoomBanner';

const viewEvent = new EventEmitter();

Expand Down Expand Up @@ -42,6 +43,7 @@ function RoomView({ roomTimeline, eventId }) {
return (
<div className="room-view" ref={roomViewRef}>
<RoomViewHeader roomId={roomId} />
<RoomBanner roomId={roomId} />
<div className="room-view__content-wrapper">
<div className="room-view__scrollable">
<RoomViewContent
Expand Down