mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 11:31:57 +03:00
UBERF-4127 (#4137)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
e50bdd461b
commit
d2b1e64b65
@ -983,6 +983,9 @@ dependencies:
|
||||
minio:
|
||||
specifier: ^7.0.26
|
||||
version: 7.1.3
|
||||
moment-timezone:
|
||||
specifier: ^0.5.43
|
||||
version: 0.5.43
|
||||
mongodb:
|
||||
specifier: ^4.11.0
|
||||
version: 4.17.1
|
||||
@ -13221,6 +13224,16 @@ packages:
|
||||
resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==}
|
||||
dev: false
|
||||
|
||||
/moment-timezone@0.5.43:
|
||||
resolution: {integrity: sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==}
|
||||
dependencies:
|
||||
moment: 2.29.4
|
||||
dev: false
|
||||
|
||||
/moment@2.29.4:
|
||||
resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
|
||||
dev: false
|
||||
|
||||
/mongodb-connection-string-url@2.6.0:
|
||||
resolution: {integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==}
|
||||
dependencies:
|
||||
@ -17768,7 +17781,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/calendar-resources.tgz(@types/node@16.11.68)(esbuild@0.16.17)(postcss-load-config@4.0.1)(postcss@8.4.31)(ts-node@10.9.1):
|
||||
resolution: {integrity: sha512-uhWVaA9LfyRGkkRYOipr4pcykZVqdl5EHUGCF146vAHuv01YV+njwZCeSRzbDYEB9VzQdPMdhh6/Wol8Zm3ENg==, tarball: file:projects/calendar-resources.tgz}
|
||||
resolution: {integrity: sha512-GKA5RNUEh4K+pp2mAf479tKTKebnRqldRDNln/RgNekUVHs/vqOuzHbu/4uHlIpC1QJXxyi7H+m6lidp5bqv7A==, tarball: file:projects/calendar-resources.tgz}
|
||||
id: file:projects/calendar-resources.tgz
|
||||
name: '@rush-temp/calendar-resources'
|
||||
version: 0.0.0
|
||||
@ -17785,6 +17798,7 @@ packages:
|
||||
eslint-plugin-svelte3: 4.0.0(eslint@8.51.0)(svelte@3.55.1)
|
||||
fast-equals: 2.0.4
|
||||
jest: 29.7.0(@types/node@16.11.68)(ts-node@10.9.1)
|
||||
moment-timezone: 0.5.43
|
||||
prettier: 3.1.0
|
||||
prettier-plugin-svelte: 3.1.0(prettier@3.1.0)(svelte@4.2.5)
|
||||
sass: 1.69.0
|
||||
@ -23711,7 +23725,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/ui.tgz(@types/node@16.11.68)(esbuild@0.16.17)(postcss-load-config@4.0.1)(postcss@8.4.31)(ts-node@10.9.1):
|
||||
resolution: {integrity: sha512-g5wJSxU0oHaWmOknjGHp3d+ML2V2bnveZV51xeHaq5GfbEwCdHat3DOsEt6zC3BMVRZsyJz8EmwNnd6A+KZYcA==, tarball: file:projects/ui.tgz}
|
||||
resolution: {integrity: sha512-N7xpf37pbt76Fi7r6f4ioMRsUhBC6xMQmAliUP5wX0OLlzS/sU7SHQFqY5BYcXBV9HhyTcRqQ3cIG2yGgQivDQ==, tarball: file:projects/ui.tgz}
|
||||
id: file:projects/ui.tgz
|
||||
name: '@rush-temp/ui'
|
||||
version: 0.0.0
|
||||
@ -23731,6 +23745,7 @@ packages:
|
||||
fast-equals: 2.0.4
|
||||
jest: 29.7.0(@types/node@16.11.68)(ts-node@10.9.1)
|
||||
just-clone: 6.2.0
|
||||
moment-timezone: 0.5.43
|
||||
prettier: 3.1.0
|
||||
prettier-plugin-svelte: 3.1.0(prettier@3.1.0)(svelte@4.2.5)
|
||||
sass: 1.69.0
|
||||
|
@ -117,11 +117,14 @@ export class TEvent extends TAttachedDoc implements Event {
|
||||
access!: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
|
||||
visibility?: Visibility
|
||||
|
||||
timeZone?: string
|
||||
}
|
||||
|
||||
@Model(calendar.class.ReccuringEvent, calendar.class.Event)
|
||||
@UX(calendar.string.ReccuringEvent, calendar.icon.Calendar)
|
||||
export class TReccuringEvent extends TEvent implements ReccuringEvent {
|
||||
declare timeZone: string
|
||||
rules!: RecurringRule[]
|
||||
exdate!: Timestamp[]
|
||||
rdate!: Timestamp[]
|
||||
@ -132,7 +135,6 @@ export class TReccuringEvent extends TEvent implements ReccuringEvent {
|
||||
@UX(calendar.string.Event, calendar.icon.Calendar)
|
||||
export class TReccuringInstance extends TReccuringEvent implements ReccuringInstance {
|
||||
recurringEventId!: Ref<ReccuringEvent>
|
||||
declare originalStartTime: number
|
||||
isCancelled?: boolean
|
||||
virtual?: boolean
|
||||
}
|
||||
|
@ -13,10 +13,15 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type Calendar, type Event, type ReccuringEvent } from '@hcengineering/calendar'
|
||||
import { calendarId, type Calendar, type Event, type ReccuringEvent } from '@hcengineering/calendar'
|
||||
import contact from '@hcengineering/contact'
|
||||
import core, { type Ref, TxOperations } from '@hcengineering/core'
|
||||
import { type MigrateOperation, type MigrationClient, type MigrationUpgradeClient } from '@hcengineering/model'
|
||||
import core, { TxOperations, type Ref } from '@hcengineering/core'
|
||||
import {
|
||||
tryMigrate,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||
import { DOMAIN_SETTING } from '@hcengineering/model-setting'
|
||||
import { type Integration } from '@hcengineering/setting'
|
||||
@ -121,6 +126,17 @@ async function migrateSync (client: MigrationClient): Promise<void> {
|
||||
)
|
||||
}
|
||||
|
||||
async function migrateTimezone (client: MigrationClient): Promise<void> {
|
||||
await client.update(
|
||||
DOMAIN_CALENDAR,
|
||||
{
|
||||
_class: { $in: [calendar.class.ReccuringEvent, calendar.class.ReccuringInstance] },
|
||||
timeZone: { $exists: false }
|
||||
},
|
||||
{ timeZone: 'Etc/GMT' }
|
||||
)
|
||||
}
|
||||
|
||||
export const calendarOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {
|
||||
await fixEventDueDate(client)
|
||||
@ -128,6 +144,12 @@ export const calendarOperation: MigrateOperation = {
|
||||
await fillOriginalStartTime(client)
|
||||
await migrateSync(client)
|
||||
await migrateExternalCalendars(client)
|
||||
await tryMigrate(client, calendarId, [
|
||||
{
|
||||
state: 'timezone',
|
||||
func: migrateTimezone
|
||||
}
|
||||
])
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
|
@ -43,7 +43,8 @@
|
||||
"svelte": "^4.2.5",
|
||||
"fast-equals": "^2.0.3",
|
||||
"autolinker": "4.0.0",
|
||||
"emoji-regex": "^10.1.0"
|
||||
"emoji-regex": "^10.1.0",
|
||||
"moment-timezone": "^0.5.43"
|
||||
},
|
||||
"repository": "https://github.com/hcenginneing/anticrm",
|
||||
"publishConfig": {
|
||||
|
@ -27,7 +27,7 @@
|
||||
IconChevronDown,
|
||||
ActionIcon,
|
||||
IconUndo
|
||||
} from '../..'
|
||||
} from '..'
|
||||
|
||||
interface TimeZoneGroup {
|
||||
continent: string
|
||||
@ -38,6 +38,7 @@
|
||||
export let timeZones: TimeZone[] = []
|
||||
export let count: number
|
||||
export let reset: string | null
|
||||
export let withAdd: boolean = true
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -142,18 +143,20 @@
|
||||
{#each items as item}
|
||||
<button class="menu-item no-focus items-center" on:click={() => dispatch('close', item.id)}>
|
||||
<span class="overflow-label label flex-grow">{item.city}</span>
|
||||
<div class="tool ml-2">
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
size={'small'}
|
||||
kind={'ghost'}
|
||||
disabled={count > 4}
|
||||
on:click={() => {
|
||||
count++
|
||||
dispatch('update', item.id)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{#if withAdd}
|
||||
<div class="tool ml-2">
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
size={'small'}
|
||||
kind={'ghost'}
|
||||
disabled={count > 4}
|
||||
on:click={() => {
|
||||
count++
|
||||
dispatch('update', item.id)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
@ -18,11 +18,13 @@
|
||||
import Icon from '../Icon.svelte'
|
||||
import Label from '../Label.svelte'
|
||||
import IconClose from '../icons/Close.svelte'
|
||||
import { daysInMonth } from './internal/DateUtils'
|
||||
import { daysInMonth, getUserTimezone } from './internal/DateUtils'
|
||||
import moment from 'moment-timezone'
|
||||
|
||||
export let currentDate: Date | null
|
||||
export let withTime: boolean = false
|
||||
export let kind: 'default' | 'plain' = 'default'
|
||||
export let timeZone: string = getUserTimezone()
|
||||
|
||||
type TEdits = 'day' | 'month' | 'year' | 'hour' | 'min'
|
||||
interface IEdits {
|
||||
@ -44,19 +46,31 @@
|
||||
if (date == null) date = new Date()
|
||||
switch (id) {
|
||||
case 'day':
|
||||
date = new Date(timeZone ? moment(date).tz(timeZone).date(val).valueOf() : moment(date).date(val).valueOf())
|
||||
date.setDate(val)
|
||||
break
|
||||
case 'month':
|
||||
date.setMonth(val - 1)
|
||||
date = new Date(
|
||||
timeZone
|
||||
? moment(date)
|
||||
.tz(timeZone)
|
||||
.month(val + 1)
|
||||
.valueOf()
|
||||
: moment(date)
|
||||
.month(val + 1)
|
||||
.valueOf()
|
||||
)
|
||||
break
|
||||
case 'year':
|
||||
date.setFullYear(val)
|
||||
date = new Date(timeZone ? moment(date).tz(timeZone).year(val).valueOf() : moment(date).year(val).valueOf())
|
||||
break
|
||||
case 'hour':
|
||||
date.setHours(val)
|
||||
date = new Date(timeZone ? moment(date).tz(timeZone).hours(val).valueOf() : moment(date).hours(val).valueOf())
|
||||
break
|
||||
case 'min':
|
||||
date.setMinutes(val)
|
||||
date = new Date(
|
||||
timeZone ? moment(date).tz(timeZone).minutes(val).valueOf() : moment(date).minutes(val).valueOf()
|
||||
)
|
||||
break
|
||||
}
|
||||
return date
|
||||
@ -81,15 +95,15 @@
|
||||
const getValue = (date: Date, id: TEdits): number => {
|
||||
switch (id) {
|
||||
case 'day':
|
||||
return date.getDate()
|
||||
return timeZone ? moment(date).tz(timeZone).date() : moment(date).date()
|
||||
case 'month':
|
||||
return date.getMonth() + 1
|
||||
return timeZone ? moment(date).tz(timeZone).month() + 1 : moment(date).month() + 1
|
||||
case 'year':
|
||||
return date.getFullYear()
|
||||
return timeZone ? moment(date).tz(timeZone).year() : moment(date).year()
|
||||
case 'hour':
|
||||
return date.getHours()
|
||||
return timeZone ? moment(date).tz(timeZone).hours() : moment(date).hours()
|
||||
case 'min':
|
||||
return date.getMinutes()
|
||||
return timeZone ? moment(date).tz(timeZone).minutes() : moment(date).minutes()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,11 +19,12 @@
|
||||
import {
|
||||
ActionIcon,
|
||||
Button,
|
||||
Scroller,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
checkAdaptiveMatching,
|
||||
IconClose,
|
||||
Label,
|
||||
IconClose
|
||||
Scroller,
|
||||
checkAdaptiveMatching,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
getUserTimezone
|
||||
} from '../..'
|
||||
import ui from '../../plugin'
|
||||
import DateInputBox from './DateInputBox.svelte'
|
||||
@ -36,6 +37,7 @@
|
||||
export let label = currentDate != null ? ui.string.EditDueDate : ui.string.AddDueDate
|
||||
export let detail: IntlString | undefined = undefined
|
||||
export let noShift: boolean = false
|
||||
export let timeZone: string = getUserTimezone()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -110,6 +112,7 @@
|
||||
bind:this={dateInput}
|
||||
bind:currentDate
|
||||
{withTime}
|
||||
{timeZone}
|
||||
kind={'plain'}
|
||||
on:close={() => {
|
||||
closeDP(withTime)
|
||||
@ -126,6 +129,7 @@
|
||||
<MonthSquare
|
||||
bind:currentDate
|
||||
{viewDate}
|
||||
{timeZone}
|
||||
{mondayStart}
|
||||
viewUpdate={false}
|
||||
hideNavigator={'all'}
|
||||
@ -140,6 +144,7 @@
|
||||
bind:currentDate
|
||||
viewDate={viewDateSec}
|
||||
{mondayStart}
|
||||
{timeZone}
|
||||
viewUpdate={false}
|
||||
noPadding
|
||||
on:update={(result) => {
|
||||
@ -158,6 +163,7 @@
|
||||
bind:currentDate
|
||||
{viewDate}
|
||||
{mondayStart}
|
||||
{timeZone}
|
||||
viewUpdate={false}
|
||||
hideNavigator={'all'}
|
||||
noPadding
|
||||
@ -169,6 +175,7 @@
|
||||
<div class="space" />
|
||||
<MonthSquare
|
||||
bind:currentDate
|
||||
{timeZone}
|
||||
viewDate={viewDateSec}
|
||||
{mondayStart}
|
||||
viewUpdate={false}
|
||||
|
@ -14,23 +14,26 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { afterUpdate, createEventDispatcher } from 'svelte'
|
||||
import IconNavPrev from '../icons/NavPrev.svelte'
|
||||
import IconNavNext from '../icons/NavNext.svelte'
|
||||
import Icon from '../Icon.svelte'
|
||||
import {
|
||||
firstDay,
|
||||
day,
|
||||
getWeekDayName,
|
||||
areDatesEqual,
|
||||
getMonthName,
|
||||
daysInMonth,
|
||||
TCellStyle,
|
||||
ICell
|
||||
} from './internal/DateUtils'
|
||||
import { capitalizeFirstLetter } from '../../utils'
|
||||
import Icon from '../Icon.svelte'
|
||||
import IconNavNext from '../icons/NavNext.svelte'
|
||||
import IconNavPrev from '../icons/NavPrev.svelte'
|
||||
import {
|
||||
ICell,
|
||||
TCellStyle,
|
||||
areDatesEqual,
|
||||
day,
|
||||
daysInMonth,
|
||||
firstDay,
|
||||
getMonthName,
|
||||
getUserTimezone,
|
||||
getWeekDayName
|
||||
} from './internal/DateUtils'
|
||||
import moment from 'moment-timezone'
|
||||
|
||||
export let currentDate: Date | null
|
||||
export let mondayStart: boolean = true
|
||||
export let timeZone: string = getUserTimezone()
|
||||
export let hideNavigator: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -46,7 +49,16 @@
|
||||
|
||||
let days: ICell[] = []
|
||||
const getDateStyle = (date: Date): TCellStyle => {
|
||||
if (currentDate != null && areDatesEqual(currentDate, date)) return 'selected'
|
||||
if (currentDate != null) {
|
||||
const zonedTime = moment(currentDate).tz(timeZone)
|
||||
if (
|
||||
zonedTime.date() === date.getDate() &&
|
||||
zonedTime.year() === date.getFullYear() &&
|
||||
zonedTime.month() === date.getMonth()
|
||||
) {
|
||||
return 'selected'
|
||||
}
|
||||
}
|
||||
return 'not-selected'
|
||||
}
|
||||
const renderCellStyles = (): void => {
|
||||
|
@ -17,8 +17,18 @@
|
||||
import IconArrowLeft from '../icons/ArrowLeft.svelte'
|
||||
import IconArrowRight from '../icons/ArrowRight.svelte'
|
||||
import Button from '../Button.svelte'
|
||||
import { firstDay, day, getWeekDayName, areDatesEqual, getMonthName, weekday, isWeekend } from './internal/DateUtils'
|
||||
import {
|
||||
firstDay,
|
||||
day,
|
||||
getWeekDayName,
|
||||
areDatesEqual,
|
||||
getMonthName,
|
||||
weekday,
|
||||
isWeekend,
|
||||
getUserTimezone
|
||||
} from './internal/DateUtils'
|
||||
import { capitalizeFirstLetter } from '../../utils'
|
||||
import moment from 'moment-timezone'
|
||||
|
||||
export let currentDate: Date | null
|
||||
export let viewDate: Date
|
||||
@ -27,6 +37,7 @@
|
||||
export let viewUpdate: boolean = true
|
||||
export let noPadding: boolean = false
|
||||
export let displayedWeeksCount = 6
|
||||
export let timeZone: string = getUserTimezone()
|
||||
export let selectedTo: Date | null | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -49,8 +60,26 @@
|
||||
}
|
||||
|
||||
function isSelected (currentDate: Date | null, selectedTo: Date | null | undefined, target: Date): boolean {
|
||||
if (currentDate != null && areDatesEqual(currentDate, target)) return true
|
||||
if (selectedTo != null && areDatesEqual(selectedTo, target)) return true
|
||||
if (currentDate != null) {
|
||||
const zonedTime = moment(currentDate).tz(timeZone)
|
||||
if (
|
||||
zonedTime.date() === target.getDate() &&
|
||||
zonedTime.year() === target.getFullYear() &&
|
||||
zonedTime.month() === target.getMonth()
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (selectedTo != null) {
|
||||
const zonedTime = moment(selectedTo).tz(timeZone)
|
||||
if (
|
||||
zonedTime.date() === target.getDate() &&
|
||||
zonedTime.year() === target.getFullYear() &&
|
||||
zonedTime.month() === target.getMonth()
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,10 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Month from './Month.svelte'
|
||||
import { getUserTimezone } from './internal/DateUtils'
|
||||
|
||||
export let currentDate: Date | null
|
||||
export let timeZone: string = getUserTimezone()
|
||||
export let mondayStart: boolean = true
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -25,6 +27,7 @@
|
||||
<div class="antiPopup popup">
|
||||
<Month
|
||||
bind:currentDate
|
||||
{timeZone}
|
||||
{mondayStart}
|
||||
on:update={(result) => {
|
||||
if (result.detail !== undefined) {
|
||||
|
@ -16,11 +16,13 @@
|
||||
import { afterUpdate, createEventDispatcher } from 'svelte'
|
||||
import ui from '../../plugin'
|
||||
import Label from '../Label.svelte'
|
||||
import moment from 'moment-timezone'
|
||||
|
||||
export let currentDate: Date
|
||||
export let size: 'small' | 'medium' = 'medium'
|
||||
export let noBorder: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let timeZone: string | undefined = undefined
|
||||
|
||||
type TEdits = 'hour' | 'min'
|
||||
interface IEdits {
|
||||
@ -38,14 +40,16 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const setValue = (val: number, date: Date | null, id: TEdits): Date => {
|
||||
const setValue = (val: number, date: Date | null, id: TEdits, timeZone: string | undefined): Date => {
|
||||
if (date == null) date = new Date()
|
||||
switch (id) {
|
||||
case 'hour':
|
||||
date.setHours(val)
|
||||
date = new Date(timeZone ? moment(date).tz(timeZone).hours(val).valueOf() : moment(date).hours(val).valueOf())
|
||||
break
|
||||
case 'min':
|
||||
date.setMinutes(val)
|
||||
date = new Date(
|
||||
timeZone ? moment(date).tz(timeZone).minutes(val).valueOf() : moment(date).minutes(val).valueOf()
|
||||
)
|
||||
break
|
||||
}
|
||||
return date
|
||||
@ -61,23 +65,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
const getValue = (date: Date, id: TEdits): number => {
|
||||
const getValue = (date: Date, id: TEdits, timeZone: string | undefined): number => {
|
||||
switch (id) {
|
||||
case 'hour':
|
||||
return date.getHours()
|
||||
return timeZone ? moment(date).tz(timeZone).hours() : moment(date).hours()
|
||||
case 'min':
|
||||
return date.getMinutes()
|
||||
return timeZone ? moment(date).tz(timeZone).minutes() : moment(date).minutes()
|
||||
}
|
||||
}
|
||||
|
||||
const dateToEdits = (currentDate: Date | null): void => {
|
||||
const dateToEdits = (currentDate: Date | null, timeZone: string | undefined): void => {
|
||||
if (currentDate == null) {
|
||||
edits.forEach((edit) => {
|
||||
edit.value = -1
|
||||
})
|
||||
} else {
|
||||
for (const edit of edits) {
|
||||
edit.value = getValue(currentDate, edit.id)
|
||||
edit.value = getValue(currentDate, edit.id, timeZone)
|
||||
}
|
||||
}
|
||||
edits = edits
|
||||
@ -85,7 +89,7 @@
|
||||
|
||||
export const isNull = (currentDate?: Date): boolean => {
|
||||
if (currentDate !== undefined) {
|
||||
dateToEdits(currentDate)
|
||||
dateToEdits(currentDate, timeZone)
|
||||
}
|
||||
let result: boolean = false
|
||||
edits.forEach((edit, i) => {
|
||||
@ -113,8 +117,8 @@
|
||||
}
|
||||
if (!isNull() && !startTyping) {
|
||||
fixEdits()
|
||||
currentDate = setValue(edits[index].value, currentDate, ed)
|
||||
dateToEdits(currentDate)
|
||||
currentDate = setValue(edits[index].value, currentDate, ed, timeZone)
|
||||
dateToEdits(currentDate, timeZone)
|
||||
}
|
||||
edits = edits
|
||||
dispatch('update', currentDate)
|
||||
@ -132,8 +136,8 @@
|
||||
if (edits[index].value !== -1) {
|
||||
const val = ev.code === 'ArrowUp' ? edits[index].value + 1 : edits[index].value - 1
|
||||
if (currentDate) {
|
||||
currentDate = setValue(val, currentDate, ed)
|
||||
dateToEdits(currentDate)
|
||||
currentDate = setValue(val, currentDate, ed, timeZone)
|
||||
dateToEdits(currentDate, timeZone)
|
||||
dispatch('update', currentDate)
|
||||
}
|
||||
}
|
||||
@ -160,7 +164,7 @@
|
||||
dispatch('save')
|
||||
}
|
||||
|
||||
$: dateToEdits(currentDate)
|
||||
$: dateToEdits(currentDate, timeZone)
|
||||
$: if (selected && edits[getIndex(selected)].el) edits[getIndex(selected)].el?.focus()
|
||||
|
||||
afterUpdate(() => {
|
||||
|
@ -11,6 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { type TimeZone } from '../../../types'
|
||||
|
||||
export const DAYS_IN_WEEK = 7
|
||||
|
||||
export const MILLISECONDS_IN_MINUTE = 60000
|
||||
@ -127,6 +129,26 @@ export function getFormattedDate (value: number | null): string {
|
||||
return value === null ? '' : new Date(value).toLocaleString('default', { month: 'short', day: 'numeric' })
|
||||
}
|
||||
|
||||
export const getTimeZoneName = (): string => {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone?.split('/')[1] ?? ''
|
||||
export const getTimeZoneName = (val: string = Intl.DateTimeFormat().resolvedOptions().timeZone): string => {
|
||||
return val.split('/')[1] ?? ''
|
||||
}
|
||||
|
||||
export const convertTimeZone = (tz: string): TimeZone => {
|
||||
const tzSpace = tz.replace(/_/gi, ' ')
|
||||
const parts = tzSpace.split('/')
|
||||
if (tz === '' || parts.length === 1) return { id: tz, continent: tzSpace, city: tzSpace, short: tzSpace }
|
||||
return {
|
||||
id: tz,
|
||||
continent: parts[0],
|
||||
city: parts.length > 2 ? `${parts[1]} - ${parts[2]}` : parts[1],
|
||||
short: parts.length > 2 ? parts[2] : parts[1]
|
||||
}
|
||||
}
|
||||
|
||||
export function getUserTimezone (): string {
|
||||
if (window.Intl !== undefined) {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
} else {
|
||||
return 'Etc/GMT'
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { showPopup, TimeZone } from '../..'
|
||||
import { convertTimeZone, showPopup, TimeZone } from '../..'
|
||||
import ClockFace from './ClockFace.svelte'
|
||||
import TimeZonesPopup from './TimeZonesPopup.svelte'
|
||||
import TimeZonesPopup from '../TimeZonesPopup.svelte'
|
||||
|
||||
const clockSize: string = '80px'
|
||||
const tzs: string[] = []
|
||||
@ -30,17 +30,6 @@
|
||||
if (!Intl.supportedValuesOf) console.log('Your browser does not support Intl.supportedValuesOf().')
|
||||
else for (const timeZone of Intl.supportedValuesOf('timeZone')) tzs.push(timeZone)
|
||||
|
||||
const convertTimeZone = (tz: string): TimeZone => {
|
||||
const tzSpace = tz.replaceAll('_', ' ')
|
||||
const parts = tzSpace.split('/')
|
||||
if (tz === '' || parts.length === 1) return { id: tz, continent: tzSpace, city: tzSpace, short: tzSpace }
|
||||
return {
|
||||
id: tz,
|
||||
continent: parts[0],
|
||||
city: parts.length > 2 ? `${parts[1]} - ${parts[2]}` : parts[1],
|
||||
short: parts.length > 2 ? parts[2] : parts[1]
|
||||
}
|
||||
}
|
||||
if (tzs.length > 0) tzs.forEach((tz) => timeZones.push(convertTimeZone(tz)))
|
||||
|
||||
const saveTZ = (): void => {
|
||||
|
@ -209,6 +209,7 @@ export { default as ModeSelector } from './components/ModeSelector.svelte'
|
||||
export { default as SimpleTimePopup } from './components/calendar/SimpleTimePopup.svelte'
|
||||
export { default as NumberInput } from './components/NumberInput.svelte'
|
||||
export { default as Lazy } from './components/Lazy.svelte'
|
||||
export { default as TimeZonesPopup } from './components/TimeZonesPopup.svelte'
|
||||
|
||||
export * from './types'
|
||||
export * from './location'
|
||||
|
@ -51,6 +51,7 @@
|
||||
"@hcengineering/view-resources": "^0.6.0",
|
||||
"@hcengineering/view": "^0.6.9",
|
||||
"@hcengineering/workbench": "^0.6.9",
|
||||
"fast-equals": "^2.0.3"
|
||||
"fast-equals": "^2.0.3",
|
||||
"moment-timezone": "^0.5.43"
|
||||
}
|
||||
}
|
||||
|
@ -18,19 +18,28 @@
|
||||
import { Class, Doc, Ref, getCurrentAccount } from '@hcengineering/core'
|
||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { StyledTextBox } from '@hcengineering/text-editor'
|
||||
import { Button, EditBox, Icon, IconClose, IconMoreH, createFocusManager, showPopup } from '@hcengineering/ui'
|
||||
import {
|
||||
Button,
|
||||
EditBox,
|
||||
FocusHandler,
|
||||
Icon,
|
||||
IconClose,
|
||||
IconMoreH,
|
||||
createFocusManager,
|
||||
getUserTimezone,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import calendar from '../plugin'
|
||||
import { saveUTC } from '../utils'
|
||||
import CalendarSelector from './CalendarSelector.svelte'
|
||||
import EventParticipants from './EventParticipants.svelte'
|
||||
import EventReminders from './EventReminders.svelte'
|
||||
import EventTimeEditor from './EventTimeEditor.svelte'
|
||||
import EventTimeExtraButton from './EventTimeExtraButton.svelte'
|
||||
import LocationEditor from './LocationEditor.svelte'
|
||||
import ReccurancePopup from './ReccurancePopup.svelte'
|
||||
import VisibilityEditor from './VisibilityEditor.svelte'
|
||||
import CalendarSelector from './CalendarSelector.svelte'
|
||||
import LocationEditor from './LocationEditor.svelte'
|
||||
import FocusHandler from '@hcengineering/ui/src/components/FocusHandler.svelte'
|
||||
|
||||
export let attachedTo: Ref<Doc> = calendar.ids.NoAttached
|
||||
export let attachedToClass: Ref<Class<Doc>> = calendar.class.Event
|
||||
@ -41,7 +50,6 @@
|
||||
const now = new Date()
|
||||
const defaultDuration = 60 * 60 * 1000
|
||||
const allDayDuration = 24 * 60 * 60 * 1000 - 1
|
||||
// const offsetTZ = new Date().getTimezoneOffset() * 60 * 1000
|
||||
|
||||
let startDate =
|
||||
date === undefined ? now.getTime() : withTime ? date.getTime() : date.setHours(now.getHours(), now.getMinutes())
|
||||
@ -49,6 +57,7 @@
|
||||
let dueDate = startDate + duration
|
||||
let allDay = false
|
||||
let location = ''
|
||||
let timeZone: string = getUserTimezone()
|
||||
|
||||
let reminders = [30 * 60 * 1000]
|
||||
|
||||
@ -99,7 +108,8 @@
|
||||
location,
|
||||
allDay,
|
||||
access: 'owner',
|
||||
originalStartTime: allDay ? saveUTC(date) : date
|
||||
originalStartTime: allDay ? saveUTC(date) : date,
|
||||
timeZone
|
||||
})
|
||||
} else {
|
||||
await client.addCollection(calendar.class.Event, space, attachedTo, attachedToClass, 'events', {
|
||||
@ -114,6 +124,7 @@
|
||||
title,
|
||||
location,
|
||||
allDay,
|
||||
timeZone,
|
||||
access: 'owner'
|
||||
})
|
||||
}
|
||||
@ -168,8 +179,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="block first flex-no-shrink">
|
||||
<EventTimeEditor {allDay} bind:startDate bind:dueDate focusIndex={10004} />
|
||||
<EventTimeExtraButton bind:allDay bind:rules on:repeat={setRecurrance} on:allday={allDayChangeHandler} />
|
||||
<EventTimeEditor {allDay} bind:startDate bind:dueDate {timeZone} focusIndex={10004} />
|
||||
<EventTimeExtraButton
|
||||
bind:allDay
|
||||
bind:timeZone
|
||||
bind:rules
|
||||
on:repeat={setRecurrance}
|
||||
on:allday={allDayChangeHandler}
|
||||
/>
|
||||
</div>
|
||||
<div class="block rightCropPadding">
|
||||
<LocationEditor focusIndex={10010} bind:value={location} />
|
||||
|
@ -19,10 +19,11 @@
|
||||
ButtonSize,
|
||||
DatePopup,
|
||||
SimpleDatePopup,
|
||||
eventToHTMLElement,
|
||||
showPopup,
|
||||
TimeInputBox,
|
||||
TimeShiftPresenter
|
||||
TimeShiftPresenter,
|
||||
eventToHTMLElement,
|
||||
getUserTimezone,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import DateLocalePresenter from './DateLocalePresenter.svelte'
|
||||
@ -36,6 +37,7 @@
|
||||
export let size: ButtonSize = 'medium'
|
||||
export let disabled: boolean = false
|
||||
export let focusIndex = -1
|
||||
export let timeZone: string = getUserTimezone()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -45,7 +47,7 @@
|
||||
if (!showDate) {
|
||||
showPopup(
|
||||
DatePopup,
|
||||
{ currentDate, withTime: !withoutTime, label: ui.string.SelectDate, noShift: true },
|
||||
{ currentDate, withTime: !withoutTime, timeZone, label: ui.string.SelectDate, noShift: true },
|
||||
undefined,
|
||||
(res) => {
|
||||
if (res) {
|
||||
@ -58,7 +60,7 @@
|
||||
}
|
||||
|
||||
function dateClick (e: MouseEvent) {
|
||||
showPopup(SimpleDatePopup, { currentDate }, eventToHTMLElement(e), (res) => {
|
||||
showPopup(SimpleDatePopup, { currentDate, timeZone }, eventToHTMLElement(e), (res) => {
|
||||
if (res) {
|
||||
date = res.getTime()
|
||||
dispatch('update', date)
|
||||
@ -80,10 +82,11 @@
|
||||
{#if showDate || withoutTime}
|
||||
<Button {kind} {size} padding={'0 .5rem'} {focusIndex} on:click={dateClick} {disabled}>
|
||||
<svelte:fragment slot="content">
|
||||
<DateLocalePresenter date={currentDate.getTime()} />
|
||||
<DateLocalePresenter date={currentDate.getTime()} {timeZone} />
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
{#if !withoutTime}
|
||||
<Button
|
||||
{kind}
|
||||
@ -96,6 +99,7 @@
|
||||
<svelte:fragment slot="content">
|
||||
<TimeInputBox
|
||||
bind:currentDate
|
||||
{timeZone}
|
||||
noBorder
|
||||
size={'small'}
|
||||
on:update={(date) => {
|
||||
|
@ -13,9 +13,14 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getUserTimezone } from '@hcengineering/ui'
|
||||
|
||||
export let date: number
|
||||
export let timeZone: string = getUserTimezone()
|
||||
|
||||
const current = new Date()
|
||||
let options: Intl.DateTimeFormatOptions = {
|
||||
timeZone,
|
||||
day: 'numeric',
|
||||
weekday: 'short',
|
||||
month: 'short'
|
||||
@ -26,6 +31,8 @@
|
||||
year: '2-digit'
|
||||
}
|
||||
}
|
||||
|
||||
$: options.timeZone = timeZone
|
||||
</script>
|
||||
|
||||
{new Date(date).toLocaleDateString('default', options)}
|
||||
|
@ -18,20 +18,28 @@
|
||||
import { DocumentUpdate, Ref } from '@hcengineering/core'
|
||||
import presentation, { getClient } from '@hcengineering/presentation'
|
||||
import { StyledTextBox } from '@hcengineering/text-editor'
|
||||
import { Button, EditBox, Icon, IconClose, createFocusManager, showPopup } from '@hcengineering/ui'
|
||||
import {
|
||||
Button,
|
||||
EditBox,
|
||||
FocusHandler,
|
||||
Icon,
|
||||
IconClose,
|
||||
createFocusManager,
|
||||
getUserTimezone,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import calendar from '../plugin'
|
||||
import { isReadOnly, saveUTC, updateReccuringInstance } from '../utils'
|
||||
import CalendarSelector from './CalendarSelector.svelte'
|
||||
import EventParticipants from './EventParticipants.svelte'
|
||||
import EventReminders from './EventReminders.svelte'
|
||||
import EventTimeEditor from './EventTimeEditor.svelte'
|
||||
import EventTimeExtraButton from './EventTimeExtraButton.svelte'
|
||||
import LocationEditor from './LocationEditor.svelte'
|
||||
import ReccurancePopup from './ReccurancePopup.svelte'
|
||||
import VisibilityEditor from './VisibilityEditor.svelte'
|
||||
import CalendarSelector from './CalendarSelector.svelte'
|
||||
import LocationEditor from './LocationEditor.svelte'
|
||||
import FocusHandler from '@hcengineering/ui/src/components/FocusHandler.svelte'
|
||||
|
||||
export let object: Event
|
||||
$: readOnly = isReadOnly(object)
|
||||
@ -48,6 +56,7 @@
|
||||
let visibility = object.visibility ?? 'public'
|
||||
let reminders = [...(object.reminders ?? [])]
|
||||
let space = object.space
|
||||
let timeZone: string = object.timeZone ?? getUserTimezone()
|
||||
|
||||
let description = object.description
|
||||
let location = object.location
|
||||
@ -84,6 +93,9 @@
|
||||
if (object.location !== location) {
|
||||
update.location = location
|
||||
}
|
||||
if (object.timeZone !== timeZone) {
|
||||
update.timeZone = timeZone
|
||||
}
|
||||
if (allDay !== object.allDay) {
|
||||
update.date = allDay ? saveUTC(startDate) : startDate
|
||||
update.dueDate = allDay ? saveUTC(dueDate) : dueDate
|
||||
@ -170,8 +182,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="block first flex-no-shrink">
|
||||
<EventTimeEditor {allDay} bind:startDate bind:dueDate disabled={readOnly} focusIndex={10004} />
|
||||
<EventTimeExtraButton bind:allDay bind:rules on:repeat={setRecurrance} on:allday={allDayChangeHandler} noRepeat />
|
||||
<EventTimeEditor {allDay} bind:startDate {timeZone} bind:dueDate disabled={readOnly} focusIndex={10004} />
|
||||
<EventTimeExtraButton
|
||||
bind:allDay
|
||||
bind:timeZone
|
||||
bind:rules
|
||||
on:repeat={setRecurrance}
|
||||
{readOnly}
|
||||
on:allday={allDayChangeHandler}
|
||||
noRepeat
|
||||
/>
|
||||
</div>
|
||||
<div class="block rightCropPadding">
|
||||
<LocationEditor bind:value={location} focusIndex={10005} />
|
||||
|
@ -13,18 +13,20 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Icon, areDatesEqual, IconArrowRight } from '@hcengineering/ui'
|
||||
import { Icon, IconArrowRight, getUserTimezone } from '@hcengineering/ui'
|
||||
import moment from 'moment-timezone'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import calendar from '../plugin'
|
||||
import DateEditor from './DateEditor.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let startDate: number
|
||||
export let dueDate: number
|
||||
export let allDay: boolean
|
||||
export let disabled: boolean = false
|
||||
export let timeZone: string = getUserTimezone()
|
||||
export let focusIndex = -1
|
||||
|
||||
$: sameDate = areDatesEqual(new Date(startDate), new Date(dueDate))
|
||||
$: sameDate = moment(startDate).tz(timeZone).isSame(moment(dueDate).tz(timeZone), 'date')
|
||||
|
||||
let diff = dueDate - startDate
|
||||
const allDayDuration = 24 * 60 * 60 * 1000 - 1
|
||||
@ -56,6 +58,7 @@
|
||||
bind:date={startDate}
|
||||
direction={sameDate ? 'horizontal' : 'vertical'}
|
||||
withoutTime={allDay}
|
||||
{timeZone}
|
||||
on:update={dateChange}
|
||||
{disabled}
|
||||
{focusIndex}
|
||||
@ -70,6 +73,7 @@
|
||||
showDate={!sameDate}
|
||||
difference={startDate}
|
||||
{disabled}
|
||||
{timeZone}
|
||||
focusIndex={focusIndex !== -1 ? focusIndex + 1 : focusIndex}
|
||||
on:update={dueChange}
|
||||
/>
|
||||
|
@ -14,28 +14,67 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { RecurringRule } from '@hcengineering/calendar'
|
||||
import { Button, CheckBox, Icon, Label, MILLISECONDS_IN_MINUTE } from '@hcengineering/ui'
|
||||
import {
|
||||
Button,
|
||||
CheckBox,
|
||||
Icon,
|
||||
Label,
|
||||
TimeZone,
|
||||
TimeZonesPopup,
|
||||
convertTimeZone,
|
||||
eventToHTMLElement,
|
||||
getUserTimezone,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import calendar from '../plugin'
|
||||
import RRulePresenter from './RRulePresenter.svelte'
|
||||
import TimeZoneSelector from './TimeZoneSelector.svelte'
|
||||
|
||||
export let allDay: boolean
|
||||
export let rules: RecurringRule[] = []
|
||||
export let noRepeat: boolean = false
|
||||
export let timeZone: string
|
||||
export let readOnly: boolean = false
|
||||
|
||||
const myTimezone = getUserTimezone()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const offsetTZ = new Date().getTimezoneOffset() * 60 * 1000
|
||||
function showTimezoneSelector (e: MouseEvent) {
|
||||
const timeZones: TimeZone[] = []
|
||||
const tzs: string[] = []
|
||||
if (!Intl.supportedValuesOf) console.log('Your browser does not support Intl.supportedValuesOf().')
|
||||
else for (const timeZone of Intl.supportedValuesOf('timeZone')) tzs.push(timeZone)
|
||||
|
||||
if (tzs.length > 0) tzs.forEach((tz) => timeZones.push(convertTimeZone(tz)))
|
||||
showPopup(
|
||||
TimeZonesPopup,
|
||||
{
|
||||
timeZones,
|
||||
withAdd: false,
|
||||
selected: timeZone,
|
||||
count: 1,
|
||||
reset: null
|
||||
},
|
||||
eventToHTMLElement(e),
|
||||
(result) => {
|
||||
if (result !== undefined) {
|
||||
timeZone = result
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if !allDay && rules.length === 0}
|
||||
{#if !allDay && rules.length === 0 && myTimezone === timeZone}
|
||||
<div class="antiButton ghost x-small sh-no-shape text-11px pl-2 pr-2 pt-1 pb-1 mt-1 ml-5-5 gap-3 w-min">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="overflow-label cursor-pointer" on:click={() => (allDay = true)}>
|
||||
<Label label={calendar.string.AllDay} />
|
||||
</div>
|
||||
<div class="overflow-label cursor-default">
|
||||
<div class="overflow-label cursor-default" on:click={showTimezoneSelector}>
|
||||
<Label label={calendar.string.TimeZone} />
|
||||
</div>
|
||||
{#if !noRepeat}
|
||||
@ -54,6 +93,7 @@
|
||||
kind={'ghost'}
|
||||
padding={'0 .5rem'}
|
||||
justify={'left'}
|
||||
disabled={readOnly}
|
||||
on:click={() => {
|
||||
allDay = !allDay
|
||||
dispatch('allday')
|
||||
@ -62,13 +102,7 @@
|
||||
</div>
|
||||
<div class="flex-row-center gap-1-5 mt-1">
|
||||
<Icon icon={calendar.icon.Globe} size={'small'} fill={'var(--theme-dark-color)'} />
|
||||
<Button label={calendar.string.TimeZone} kind={'ghost'} padding={'0 .5rem'} justify={'left'}>
|
||||
<svelte:fragment slot="content">
|
||||
<span class="ml-2 content-darker-color">
|
||||
GMT{(offsetTZ > 0 ? '-' : '+') + Math.abs(offsetTZ / MILLISECONDS_IN_MINUTE / 60)}
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
<TimeZoneSelector bind:timeZone disabled={readOnly} />
|
||||
</div>
|
||||
{#if !noRepeat}
|
||||
<div class="flex-row-center gap-1-5 mt-1">
|
||||
@ -78,6 +112,7 @@
|
||||
kind={'ghost'}
|
||||
padding={'0 .5rem'}
|
||||
justify={'left'}
|
||||
disabled={readOnly}
|
||||
on:click={() => dispatch('repeat')}
|
||||
>
|
||||
<svelte:fragment slot="content">
|
||||
|
@ -0,0 +1,62 @@
|
||||
<!--
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import {
|
||||
Button,
|
||||
TimeZone,
|
||||
TimeZonesPopup,
|
||||
convertTimeZone,
|
||||
eventToHTMLElement,
|
||||
getTimeZoneName,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import calendar from '../plugin'
|
||||
|
||||
export let timeZone: string
|
||||
export let disabled: boolean = false
|
||||
|
||||
function open (e: MouseEvent) {
|
||||
const timeZones: TimeZone[] = []
|
||||
const tzs: string[] = []
|
||||
if (!Intl.supportedValuesOf) console.log('Your browser does not support Intl.supportedValuesOf().')
|
||||
else for (const timeZone of Intl.supportedValuesOf('timeZone')) tzs.push(timeZone)
|
||||
|
||||
if (tzs.length > 0) tzs.forEach((tz) => timeZones.push(convertTimeZone(tz)))
|
||||
showPopup(
|
||||
TimeZonesPopup,
|
||||
{
|
||||
timeZones,
|
||||
withAdd: false,
|
||||
selected: timeZone,
|
||||
count: 1,
|
||||
reset: null
|
||||
},
|
||||
eventToHTMLElement(e),
|
||||
(result) => {
|
||||
if (result !== undefined) {
|
||||
timeZone = result
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<Button {disabled} label={calendar.string.TimeZone} kind={'ghost'} padding={'0 .5rem'} justify={'left'} on:click={open}>
|
||||
<svelte:fragment slot="content">
|
||||
<span class="ml-2 content-darker-color">
|
||||
{getTimeZoneName(timeZone)}
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
</Button>
|
@ -102,7 +102,8 @@ async function deleteRecHandler (res: any, object: ReccuringInstance): Promise<v
|
||||
rules: object.rules,
|
||||
exdate: object.exdate,
|
||||
visibility: object.visibility,
|
||||
access: object.access
|
||||
access: object.access,
|
||||
timeZone: object.timeZone
|
||||
},
|
||||
object._id
|
||||
)
|
||||
|
@ -162,6 +162,7 @@ export async function updateReccuringInstance (
|
||||
rules: object.rules,
|
||||
exdate: object.exdate,
|
||||
rdate: object.rdate,
|
||||
timeZone: object.timeZone,
|
||||
...ops
|
||||
},
|
||||
object._id
|
||||
|
@ -69,6 +69,7 @@ export interface ReccuringEvent extends Event {
|
||||
exdate: Timestamp[]
|
||||
rdate: Timestamp[]
|
||||
originalStartTime: Timestamp
|
||||
timeZone: string
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,6 +102,8 @@ export interface Event extends AttachedDoc {
|
||||
visibility?: Visibility
|
||||
|
||||
access: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
|
||||
timeZone?: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user