Add Timezone sharing

Allows users to share their timezone
This commit is contained in:
Dylan 2022-09-04 15:51:20 +09:30
parent ac155bbf4c
commit 91e6205f49
4 changed files with 159 additions and 0 deletions

View file

@ -0,0 +1,55 @@
import React, { useState, useEffect, useCallback } 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 currentTimezone = room.currentState.getStateEvents('in.cinny.share_timezone', userId)?.event?.content?.user_timezone;
const [timezone, setTimezone] = useState(currentTimezone);
const clearTimezone = () => {
mx.sendStateEvent(roomId, 'in.cinny.share_timezone', { }, userId);
setTimezone(null);
};
const shareTimezone = () => {
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
setTimezone(userTimezone);
mx.sendStateEvent(roomId, 'in.cinny.share_timezone', { user_timezone: userTimezone }, 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;

View file

@ -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);
}
}

View file

@ -39,6 +39,7 @@ import ChevronTopIC from '../../../../public/res/ic/outlined/chevron-top.svg';
import { useForceUpdate } from '../../hooks/useForceUpdate'; import { useForceUpdate } from '../../hooks/useForceUpdate';
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog'; import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
import RoomTimezone from '../../molecules/room-timezone/RoomTimezone';
const tabText = { const tabText = {
GENERAL: 'General', GENERAL: 'General',
@ -120,6 +121,10 @@ function GeneralSettings({ roomId }) {
<MenuHeader>Room addresses</MenuHeader> <MenuHeader>Room addresses</MenuHeader>
<RoomAliases roomId={roomId} /> <RoomAliases roomId={roomId} />
</div> </div>
<div className="room-settings__card">
<MenuHeader>Timezones</MenuHeader>
<RoomTimezone roomId={roomId} />
</div>
</> </>
); );
} }

View file

@ -36,6 +36,7 @@ function RoomViewHeader({ roomId }) {
let avatarSrc = mx.getRoom(roomId).getAvatarUrl(mx.baseUrl, 36, 36, 'crop'); let avatarSrc = mx.getRoom(roomId).getAvatarUrl(mx.baseUrl, 36, 36, 'crop');
avatarSrc = isDM ? mx.getRoom(roomId).getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, 36, 36, 'crop') : avatarSrc; avatarSrc = isDM ? mx.getRoom(roomId).getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, 36, 36, 'crop') : avatarSrc;
const roomName = mx.getRoom(roomId).name; const roomName = mx.getRoom(roomId).name;
let partnerLocalTime = null;
const roomHeaderBtnRef = useRef(null); const roomHeaderBtnRef = useRef(null);
useEffect(() => { useEffect(() => {
@ -72,6 +73,19 @@ function RoomViewHeader({ roomId }) {
); );
}; };
if (isDM) {
const room = mx.getRoom(roomId);
const partner = room.getAvatarFallbackMember();
const timezone = room.currentState.getStateEvents('in.cinny.share_timezone', partner.userId)?.event?.content?.user_timezone;
const date = new Date();
try {
partnerLocalTime = date.toLocaleTimeString([], { timeZone: timezone, hour: '2-digit', minute: '2-digit' });
} catch {
partnerLocalTime = null;
}
}
return ( return (
<Header> <Header>
<IconButton <IconButton
@ -93,6 +107,7 @@ function RoomViewHeader({ roomId }) {
</TitleWrapper> </TitleWrapper>
<RawIcon src={ChevronBottomIC} /> <RawIcon src={ChevronBottomIC} />
</button> </button>
<Text>{partnerLocalTime}</Text>
<IconButton onClick={() => toggleRoomSettings(tabText.SEARCH)} tooltip="Search" src={SearchIC} /> <IconButton onClick={() => toggleRoomSettings(tabText.SEARCH)} tooltip="Search" src={SearchIC} />
<IconButton className="room-header__drawer-btn" onClick={togglePeopleDrawer} tooltip="People" src={UserIC} /> <IconButton className="room-header__drawer-btn" onClick={togglePeopleDrawer} tooltip="People" src={UserIC} />
<IconButton className="room-header__members-btn" onClick={() => toggleRoomSettings(tabText.MEMBERS)} tooltip="Members" src={UserIC} /> <IconButton className="room-header__members-btn" onClick={() => toggleRoomSettings(tabText.MEMBERS)} tooltip="Members" src={UserIC} />