diff --git a/src/app/molecules/room-timezone/RoomTimezone.jsx b/src/app/molecules/room-timezone/RoomTimezone.jsx
new file mode 100644
index 00000000..9ca09ea2
--- /dev/null
+++ b/src/app/molecules/room-timezone/RoomTimezone.jsx
@@ -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 (
+
+ Share your timezone
+
+ 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.
+
+
+ {timezone ? `Currently shared timezone: ${timezone}` : 'You are not currently sharing a timezone'}
+
+ shareTimezone()} variant={timezone ? 'surface' : 'danger'}>
+ {timezone ? 'Update Timezone' : 'Share Timezone'}
+
+
+ clearTimezone()} disabled={!timezone}>
+ Clear Shared Timezone
+
+
+ );
+}
+
+RoomTimezone.propTypes = {
+ roomId: PropTypes.string.isRequired,
+};
+
+export default RoomTimezone;
diff --git a/src/app/molecules/room-timezone/RoomTimezone.scss b/src/app/molecules/room-timezone/RoomTimezone.scss
new file mode 100644
index 00000000..9fb17922
--- /dev/null
+++ b/src/app/molecules/room-timezone/RoomTimezone.scss
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/src/app/organisms/room/RoomSettings.jsx b/src/app/organisms/room/RoomSettings.jsx
index 63277347..09e6af51 100644
--- a/src/app/organisms/room/RoomSettings.jsx
+++ b/src/app/organisms/room/RoomSettings.jsx
@@ -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',
@@ -120,6 +121,10 @@ function GeneralSettings({ roomId }) {
Room addresses
+
+ Timezones
+
+
>
);
}
diff --git a/src/app/organisms/room/RoomViewHeader.jsx b/src/app/organisms/room/RoomViewHeader.jsx
index 849ba14b..48e3bf83 100644
--- a/src/app/organisms/room/RoomViewHeader.jsx
+++ b/src/app/organisms/room/RoomViewHeader.jsx
@@ -36,6 +36,7 @@ function RoomViewHeader({ roomId }) {
let avatarSrc = mx.getRoom(roomId).getAvatarUrl(mx.baseUrl, 36, 36, 'crop');
avatarSrc = isDM ? mx.getRoom(roomId).getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, 36, 36, 'crop') : avatarSrc;
const roomName = mx.getRoom(roomId).name;
+ let partnerLocalTime = null;
const roomHeaderBtnRef = useRef(null);
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 (
+ {partnerLocalTime}
toggleRoomSettings(tabText.SEARCH)} tooltip="Search" src={SearchIC} />
toggleRoomSettings(tabText.MEMBERS)} tooltip="Members" src={UserIC} />