DEV: Convert group timezones from widgets to glimmer (#731)
Also introduces a basic system spec for the feature (previously there was no test coverage of the frontend at all)
This commit is contained in:
parent
8152a0ca7c
commit
d471bbdf9a
|
|
@ -0,0 +1,35 @@
|
|||
import { apiInitializer } from "discourse/lib/api";
|
||||
import GroupTimezones from "../components/group-timezones";
|
||||
|
||||
const GroupTimezonesShim = <template>
|
||||
<GroupTimezones
|
||||
@members={{@data.members}}
|
||||
@group={{@data.group}}
|
||||
@size={{@data.size}}
|
||||
/>
|
||||
</template>;
|
||||
|
||||
export default apiInitializer((api) => {
|
||||
api.decorateCookedElement((element, helper) => {
|
||||
element.querySelectorAll(".group-timezones").forEach((el) => {
|
||||
const post = helper.getModel();
|
||||
|
||||
if (!post) {
|
||||
return;
|
||||
}
|
||||
|
||||
const group = el.dataset.group;
|
||||
if (!group) {
|
||||
throw new Error(
|
||||
"Group timezone element is missing 'data-group' attribute"
|
||||
);
|
||||
}
|
||||
|
||||
helper.renderGlimmer(el, GroupTimezonesShim, {
|
||||
group,
|
||||
members: (post.group_timezones || {})[group] || [],
|
||||
size: el.dataset.size || "medium",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,38 +1,27 @@
|
|||
import hbs from "discourse/widgets/hbs-compiler";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
import roundTime from "../lib/round-time";
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { fn } from "@ember/helper";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { eq } from "truth-helpers";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import roundTime from "../../lib/round-time";
|
||||
import NewDay from "./new-day";
|
||||
import TimeTraveller from "./time-traveller";
|
||||
import Timezone from "./timezone";
|
||||
|
||||
export default createWidget("discourse-group-timezones", {
|
||||
tagName: "div.group-timezones",
|
||||
export default class GroupTimezones extends Component {
|
||||
@service siteSettings;
|
||||
|
||||
buildKey: (attrs) => `group-timezones-${attrs.id}`,
|
||||
@tracked filter = "";
|
||||
@tracked localTimeOffset = 0;
|
||||
|
||||
buildClasses(attrs) {
|
||||
return attrs.size;
|
||||
},
|
||||
|
||||
buildAttributes(attrs) {
|
||||
return {
|
||||
id: attrs.id,
|
||||
};
|
||||
},
|
||||
|
||||
defaultState() {
|
||||
return {
|
||||
localTimeOffset: 0,
|
||||
};
|
||||
},
|
||||
|
||||
onChangeCurrentUserTimeOffset(offset) {
|
||||
this.state.localTimeOffset = offset;
|
||||
},
|
||||
|
||||
transform(attrs, state) {
|
||||
const members = attrs.members || [];
|
||||
get groupedTimezones() {
|
||||
let groupedTimezones = [];
|
||||
|
||||
members.filterBy("timezone").forEach((member) => {
|
||||
if (this._shouldAddMemberToGroup(this.state.filter, member)) {
|
||||
this.args.members.filterBy("timezone").forEach((member) => {
|
||||
if (this.#shouldAddMemberToGroup(this.filter, member)) {
|
||||
const timezone = member.timezone;
|
||||
const identifier = parseInt(moment.tz(timezone).format("YYYYMDHm"), 10);
|
||||
let groupedTimezone = groupedTimezones.findBy("identifier", identifier);
|
||||
|
|
@ -40,18 +29,18 @@ export default createWidget("discourse-group-timezones", {
|
|||
if (groupedTimezone) {
|
||||
groupedTimezone.members.push(member);
|
||||
} else {
|
||||
const now = this._roundMoment(moment.tz(timezone));
|
||||
const workingDays = this._workingDays();
|
||||
const now = this.#roundMoment(moment.tz(timezone));
|
||||
const workingDays = this.#workingDays();
|
||||
const offset = moment.tz(moment.utc(), timezone).utcOffset();
|
||||
|
||||
groupedTimezone = {
|
||||
identifier,
|
||||
offset,
|
||||
type: "discourse-group-timezone",
|
||||
nowWithOffset: now.add(state.localTimeOffset, "minutes"),
|
||||
closeToWorkingHours: this._closeToWorkingHours(now, workingDays),
|
||||
inWorkingHours: this._inWorkingHours(now, workingDays),
|
||||
utcOffset: this._utcOffset(offset),
|
||||
nowWithOffset: now.add(this.localTimeOffset, "minutes"),
|
||||
closeToWorkingHours: this.#closeToWorkingHours(now, workingDays),
|
||||
inWorkingHours: this.#inWorkingHours(now, workingDays),
|
||||
utcOffset: this.#utcOffset(offset),
|
||||
members: [member],
|
||||
};
|
||||
groupedTimezones.push(groupedTimezone);
|
||||
|
|
@ -84,36 +73,10 @@ export default createWidget("discourse-group-timezones", {
|
|||
});
|
||||
}
|
||||
|
||||
return { groupedTimezones };
|
||||
},
|
||||
return groupedTimezones;
|
||||
}
|
||||
|
||||
onChangeFilter(filter) {
|
||||
this.state.filter = filter && filter.length ? filter : null;
|
||||
},
|
||||
|
||||
template: hbs`
|
||||
{{attach
|
||||
widget="discourse-group-timezones-header"
|
||||
attrs=(hash
|
||||
id=attrs.id
|
||||
group=attrs.group
|
||||
localTimeOffset=state.localTimeOffset
|
||||
)
|
||||
}}
|
||||
<div class="group-timezones-body">
|
||||
{{#each transformed.groupedTimezones as |groupedTimezone|}}
|
||||
{{attach
|
||||
widget=groupedTimezone.type
|
||||
attrs=(hash
|
||||
usersOnHoliday=attrs.usersOnHoliday
|
||||
groupedTimezone=groupedTimezone
|
||||
)
|
||||
}}
|
||||
{{/each}}
|
||||
</div>
|
||||
`,
|
||||
|
||||
_shouldAddMemberToGroup(filter, member) {
|
||||
#shouldAddMemberToGroup(filter, member) {
|
||||
if (filter) {
|
||||
filter = filter.toLowerCase();
|
||||
if (
|
||||
|
|
@ -127,17 +90,17 @@ export default createWidget("discourse-group-timezones", {
|
|||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
_roundMoment(date) {
|
||||
if (this.state.localTimeOffset) {
|
||||
#roundMoment(date) {
|
||||
if (this.localTimeOffset) {
|
||||
date = roundTime(date);
|
||||
}
|
||||
|
||||
return date;
|
||||
},
|
||||
}
|
||||
|
||||
_closeToWorkingHours(moment, workingDays) {
|
||||
#closeToWorkingHours(moment, workingDays) {
|
||||
const hours = moment.hours();
|
||||
const startHour = this.siteSettings.working_day_start_hour;
|
||||
const endHour = this.siteSettings.working_day_end_hour;
|
||||
|
|
@ -148,18 +111,18 @@ export default createWidget("discourse-group-timezones", {
|
|||
(hours <= Math.min(endHour + extension, 23) && hours >= endHour)) &&
|
||||
workingDays.includes(moment.isoWeekday())
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_inWorkingHours(moment, workingDays) {
|
||||
#inWorkingHours(moment, workingDays) {
|
||||
const hours = moment.hours();
|
||||
return (
|
||||
hours > this.siteSettings.working_day_start_hour &&
|
||||
hours < this.siteSettings.working_day_end_hour &&
|
||||
workingDays.includes(moment.isoWeekday())
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_utcOffset(offset) {
|
||||
#utcOffset(offset) {
|
||||
const sign = Math.sign(offset) === 1 ? "+" : "-";
|
||||
offset = Math.abs(offset);
|
||||
let hours = Math.floor(offset / 60).toString();
|
||||
|
|
@ -170,9 +133,9 @@ export default createWidget("discourse-group-timezones", {
|
|||
/:00$/,
|
||||
""
|
||||
)}`.replace(/-0/, " ");
|
||||
},
|
||||
}
|
||||
|
||||
_workingDays() {
|
||||
#workingDays() {
|
||||
const enMoment = moment().locale("en");
|
||||
const getIsoWeekday = (day) =>
|
||||
enMoment.localeData()._weekdays.indexOf(day) || 7;
|
||||
|
|
@ -180,5 +143,40 @@ export default createWidget("discourse-group-timezones", {
|
|||
.split("|")
|
||||
.filter(Boolean)
|
||||
.map((x) => getIsoWeekday(x));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
handleFilterChange(event) {
|
||||
this.filter = event.target.value;
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="group-timezones-header">
|
||||
<TimeTraveller
|
||||
@localTimeOffset={{this.localTimeOffset}}
|
||||
@setOffset={{fn (mut this.localTimeOffset)}}
|
||||
/>
|
||||
<span class="title">
|
||||
{{i18n "group_timezones.group_availability" group=@group}}
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={{i18n "group_timezones.search"}}
|
||||
class="group-timezones-filter"
|
||||
{{on "input" this.handleFilterChange}}
|
||||
/>
|
||||
</div>
|
||||
<div class="group-timezones-body">
|
||||
{{#each this.groupedTimezones key="identifier" as |groupedTimezone|}}
|
||||
{{#if (eq groupedTimezone.type "discourse-group-timezone-new-day")}}
|
||||
<NewDay
|
||||
@beforeDate={{groupedTimezone.beforeDate}}
|
||||
@afterDate={{groupedTimezone.afterDate}}
|
||||
/>
|
||||
{{else}}
|
||||
<Timezone @groupedTimezone={{groupedTimezone}} />
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</template>
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import icon from "discourse/helpers/d-icon";
|
||||
|
||||
const NewDay = <template>
|
||||
<div class="group-timezone-new-day">
|
||||
<span class="before">
|
||||
{{icon "chevron-left"}}
|
||||
{{@beforeDate}}
|
||||
</span>
|
||||
<span class="after">
|
||||
{{@afterDate}}
|
||||
{{icon "chevron-right"}}
|
||||
</span>
|
||||
</div>
|
||||
</template>;
|
||||
|
||||
export default NewDay;
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { not } from "truth-helpers";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import roundTime from "../../lib/round-time";
|
||||
|
||||
export default class TimeTraveller extends Component {
|
||||
get localTimeWithOffset() {
|
||||
let date = moment().add(this.args.localTimeOffset, "minutes");
|
||||
|
||||
if (this.args.localTimeOffset) {
|
||||
date = roundTime(date);
|
||||
}
|
||||
|
||||
return date.format("HH:mm");
|
||||
}
|
||||
|
||||
@action
|
||||
reset() {
|
||||
this.args.setOffset(0);
|
||||
}
|
||||
|
||||
@action
|
||||
sliderMoved(event) {
|
||||
const value = parseInt(event.target.value, 10);
|
||||
const offset = value * 15;
|
||||
this.args.setOffset(offset);
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="group-timezones-time-traveler">
|
||||
<span class="time">
|
||||
{{this.localTimeWithOffset}}
|
||||
</span>
|
||||
|
||||
<span class="discourse-group-timezones-slider-wrapper">
|
||||
<input
|
||||
class="group-timezones-slider"
|
||||
{{on "input" this.sliderMoved}}
|
||||
step="1"
|
||||
value="0"
|
||||
type="range"
|
||||
min="-48"
|
||||
max="48"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<div class="group-timezones-reset">
|
||||
<DButton
|
||||
disabled={{not @localTimeOffset}}
|
||||
@action={{this.reset}}
|
||||
@icon="arrow-rotate-left"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import Component from "@glimmer/component";
|
||||
import UserAvatar from "discourse/components/user-avatar";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
|
||||
export default class GroupTimezone extends Component {
|
||||
get formattedTime() {
|
||||
return this.args.groupedTimezone.nowWithOffset.format("LT");
|
||||
}
|
||||
|
||||
<template>
|
||||
<div
|
||||
class={{concatClass
|
||||
"group-timezone"
|
||||
(if @groupedTimezone.closeToWorkingHours "close-to-working-hours")
|
||||
(if @groupedTimezone.inWorkingHours "in-working-hours")
|
||||
}}
|
||||
>
|
||||
<div class="info">
|
||||
<span class="time">
|
||||
{{this.formattedTime}}
|
||||
</span>
|
||||
<span class="offset" title="UTC offset">
|
||||
{{@groupedTimezone.utcOffset}}
|
||||
</span>
|
||||
</div>
|
||||
<ul class="group-timezones-members">
|
||||
{{#each @groupedTimezone.members key="username" as |member|}}
|
||||
<li
|
||||
class={{concatClass
|
||||
"group-timezones-member"
|
||||
(if member.on_holiday "on-holiday" "not-on-holiday")
|
||||
}}
|
||||
>
|
||||
<UserAvatar
|
||||
@user={{member}}
|
||||
@size="small"
|
||||
class="group-timezones-member-avatar"
|
||||
/>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
import $ from "jquery";
|
||||
import { getRegister } from "discourse/lib/get-owner";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import WidgetGlue from "discourse/widgets/glue";
|
||||
|
||||
export default {
|
||||
name: "discourse-group-timezones",
|
||||
|
||||
initialize() {
|
||||
withPluginApi("0.8.7", (api) => {
|
||||
let _glued = [];
|
||||
|
||||
function cleanUp() {
|
||||
_glued.forEach((g) => g.cleanUp());
|
||||
_glued = [];
|
||||
}
|
||||
|
||||
function _attachWidget(container, options) {
|
||||
const glue = new WidgetGlue(
|
||||
"discourse-group-timezones",
|
||||
getRegister(api),
|
||||
options
|
||||
);
|
||||
glue.appendTo(container);
|
||||
_glued.push(glue);
|
||||
}
|
||||
|
||||
function _attachGroupTimezones($elem, post) {
|
||||
const $groupTimezones = $(".group-timezones", $elem);
|
||||
|
||||
if (!$groupTimezones.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$groupTimezones.each((idx, groupTimezone) => {
|
||||
const group = groupTimezone.getAttribute("data-group");
|
||||
if (!group) {
|
||||
throw "[group] attribute is necessary when using timezones.";
|
||||
}
|
||||
|
||||
const members = (post.get("group_timezones") || {})[group] || [];
|
||||
|
||||
_attachWidget(groupTimezone, {
|
||||
id: `${post.id}-${idx}`,
|
||||
members,
|
||||
group,
|
||||
usersOnHoliday:
|
||||
api.container.lookup("service:site").users_on_holiday || [],
|
||||
size: groupTimezone.getAttribute("data-size") || "medium",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _attachPostWithGroupTimezones($elem, helper) {
|
||||
if (helper) {
|
||||
const post = helper.getModel();
|
||||
|
||||
if (post) {
|
||||
api.preventCloak(post.id);
|
||||
_attachGroupTimezones($elem, post);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
api.decorateCooked(_attachPostWithGroupTimezones, {
|
||||
id: "discourse-group-timezones",
|
||||
});
|
||||
|
||||
api.cleanupStream(cleanUp);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import hbs from "discourse/widgets/hbs-compiler";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
|
||||
export default createWidget("discourse-group-timezone-new-day", {
|
||||
tagName: "div.group-timezone-new-day",
|
||||
|
||||
template: hbs`
|
||||
<span class="before">
|
||||
{{d-icon "chevron-left"}}
|
||||
{{this.attrs.groupedTimezone.beforeDate}}
|
||||
</span>
|
||||
<span class="after">
|
||||
{{this.attrs.groupedTimezone.afterDate}}
|
||||
{{d-icon "chevron-right"}}
|
||||
</span>
|
||||
`,
|
||||
});
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
import hbs from "discourse/widgets/hbs-compiler";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
|
||||
export default createWidget("discourse-group-timezone", {
|
||||
tagName: "div.group-timezone",
|
||||
|
||||
buildClasses(attrs) {
|
||||
const classes = [];
|
||||
|
||||
if (attrs.groupedTimezone.closeToWorkingHours) {
|
||||
classes.push("close-to-working-hours");
|
||||
}
|
||||
|
||||
if (attrs.groupedTimezone.inWorkingHours) {
|
||||
classes.push("in-working-hours");
|
||||
}
|
||||
|
||||
return classes.join(" ");
|
||||
},
|
||||
|
||||
transform(attrs) {
|
||||
return {
|
||||
formatedTime: attrs.groupedTimezone.nowWithOffset.format("LT"),
|
||||
};
|
||||
},
|
||||
|
||||
template: hbs`
|
||||
<div class="info">
|
||||
<span class="time">
|
||||
{{transformed.formatedTime}}
|
||||
</span>
|
||||
<span class="offset" title="UTC offset">
|
||||
{{{attrs.groupedTimezone.utcOffset}}}
|
||||
</span>
|
||||
</div>
|
||||
<ul class="group-timezones-members">
|
||||
{{#each attrs.groupedTimezone.members as |member|}}
|
||||
{{attach
|
||||
widget="discourse-group-timezones-member"
|
||||
attrs=(hash
|
||||
usersOnHoliday=attrs.usersOnHoliday
|
||||
member=member
|
||||
)
|
||||
}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
`,
|
||||
});
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
import { throttle } from "@ember/runloop";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default createWidget("discourse-group-timezones-filter", {
|
||||
tagName: "input.group-timezones-filter",
|
||||
|
||||
input(event) {
|
||||
this.changeFilterThrottler(event.target.value);
|
||||
},
|
||||
|
||||
changeFilterThrottler(filter) {
|
||||
throttle(
|
||||
this,
|
||||
function () {
|
||||
this.sendWidgetAction("onChangeFilter", filter);
|
||||
},
|
||||
100
|
||||
);
|
||||
},
|
||||
|
||||
buildAttributes() {
|
||||
return {
|
||||
type: "text",
|
||||
placeholder: i18n("group_timezones.search"),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import hbs from "discourse/widgets/hbs-compiler";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default createWidget("discourse-group-timezones-header", {
|
||||
tagName: "div.group-timezones-header",
|
||||
|
||||
transform(attrs) {
|
||||
return {
|
||||
title: i18n("group_timezones.group_availability", {
|
||||
group: attrs.group,
|
||||
}),
|
||||
};
|
||||
},
|
||||
|
||||
template: hbs`
|
||||
{{attach
|
||||
widget="discourse-group-timezones-time-traveler"
|
||||
attrs=(hash
|
||||
id=attrs.id
|
||||
localTimeOffset=attrs.localTimeOffset
|
||||
)
|
||||
}}
|
||||
<span class="title">
|
||||
{{transformed.title}}
|
||||
</span>
|
||||
{{attach widget="discourse-group-timezones-filter"}}
|
||||
`,
|
||||
});
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
import { h } from "virtual-dom";
|
||||
import { formatUsername } from "discourse/lib/utilities";
|
||||
import { avatarImg } from "discourse/widgets/post";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
|
||||
export default createWidget("discourse-group-timezones-member", {
|
||||
tagName: "li.group-timezones-member",
|
||||
|
||||
buildClasses(attrs) {
|
||||
return attrs.member.on_holiday ? "on-holiday" : "not-on-holiday";
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
const { name, username, avatar_template } = attrs.member;
|
||||
|
||||
return h(
|
||||
"a",
|
||||
{
|
||||
attributes: {
|
||||
class: "group-timezones-member-avatar",
|
||||
"data-user-card": username,
|
||||
},
|
||||
},
|
||||
avatarImg("small", {
|
||||
template: avatar_template,
|
||||
username: name || formatUsername(username),
|
||||
})
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import hbs from "discourse/widgets/hbs-compiler";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
|
||||
export default createWidget("discourse-group-timezones-reset", {
|
||||
tagName: "div.group-timezones-reset",
|
||||
|
||||
onResetOffset() {
|
||||
this.sendWidgetAction("onChangeCurrentUserTimeOffset", 0);
|
||||
|
||||
const container = document.getElementById(this.attrs.id);
|
||||
const slider = container.querySelector(
|
||||
"input[type=range].group-timezones-slider"
|
||||
);
|
||||
if (slider) {
|
||||
slider.value = 0;
|
||||
}
|
||||
},
|
||||
|
||||
transform(attrs) {
|
||||
return {
|
||||
isDisabled: attrs.localTimeOffset === 0,
|
||||
};
|
||||
},
|
||||
|
||||
template: hbs`
|
||||
{{attach
|
||||
widget="button"
|
||||
attrs=(hash
|
||||
disabled=this.transformed.isDisabled
|
||||
action="onResetOffset"
|
||||
icon="arrow-rotate-left"
|
||||
)
|
||||
}}
|
||||
`,
|
||||
});
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
import { throttle } from "@ember/runloop";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
|
||||
export default createWidget("discourse-group-timezones-slider", {
|
||||
tagName: "input.group-timezones-slider",
|
||||
|
||||
input(event) {
|
||||
this._handleSliderEvent(event);
|
||||
},
|
||||
|
||||
change(event) {
|
||||
this._handleSliderEvent(event);
|
||||
},
|
||||
|
||||
changeOffsetThrottler(offset) {
|
||||
throttle(
|
||||
this,
|
||||
function () {
|
||||
this.sendWidgetAction("onChangeCurrentUserTimeOffset", offset);
|
||||
},
|
||||
75
|
||||
);
|
||||
},
|
||||
|
||||
buildAttributes() {
|
||||
return {
|
||||
step: 1,
|
||||
value: 0,
|
||||
min: -48,
|
||||
max: 48,
|
||||
type: "range",
|
||||
};
|
||||
},
|
||||
|
||||
_handleSliderEvent(event) {
|
||||
const value = parseInt(event.target.value, 10);
|
||||
const offset = value * 15;
|
||||
this.changeOffsetThrottler(offset);
|
||||
},
|
||||
});
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
import hbs from "discourse/widgets/hbs-compiler";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
import roundTime from "../lib/round-time";
|
||||
|
||||
export default createWidget("discourse-group-timezones-time-traveler", {
|
||||
tagName: "div.group-timezones-time-traveler",
|
||||
|
||||
transform(attrs) {
|
||||
let date = moment().add(attrs.localTimeOffset, "minutes");
|
||||
|
||||
if (attrs.localTimeOffset) {
|
||||
date = roundTime(date);
|
||||
}
|
||||
|
||||
return {
|
||||
localTimeWithOffset: date.format("HH:mm"),
|
||||
};
|
||||
},
|
||||
|
||||
template: hbs`
|
||||
<span class="time">
|
||||
{{transformed.localTimeWithOffset}}
|
||||
</span>
|
||||
<span class="discourse-group-timezones-slider-wrapper">
|
||||
{{attach
|
||||
widget="discourse-group-timezones-slider"
|
||||
}}
|
||||
</span>
|
||||
{{attach
|
||||
widget="discourse-group-timezones-reset"
|
||||
attrs=(hash
|
||||
id=attrs.id
|
||||
localTimeOffset=attrs.localTimeOffset
|
||||
)
|
||||
}}
|
||||
`,
|
||||
});
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe "Group timezones feature", type: :system do
|
||||
fab!(:group) { Fabricate(:group, name: "test-group") }
|
||||
|
||||
fab!(:users) do
|
||||
Fabricate
|
||||
.times(5, :user)
|
||||
.each do |user|
|
||||
user.user_option.timezone = "America/New_York"
|
||||
user.user_option.save!
|
||||
group.add(user)
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
Jobs.run_immediately!
|
||||
SiteSetting.calendar_enabled = true
|
||||
end
|
||||
|
||||
let(:post) { create_post(raw: <<~RAW) }
|
||||
[timezones group="test-group"]
|
||||
[/timezones]
|
||||
RAW
|
||||
|
||||
it "renders successfully" do
|
||||
visit(post.url)
|
||||
expect(page).to have_selector(".group-timezones")
|
||||
expect(page).to have_selector(".group-timezones-member", count: 5)
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue