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'} + + + + +
+ ); +} + +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} />