fields
forms
timezone Mismatch Field
Odoo 19 fields — timezone Mismatch Field (views)
Live preview
Interactive
Source excerpt
web/static/src/views/fields/timezone_mismatch/timezone_mismatch_field.js
import { formatDateTime } from "@web/core/l10n/dates";
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { selectionField, SelectionField } from "../selection/selection_field";
const { DateTime } = luxon;
export class TimezoneMismatchField extends SelectionField {
static template = "web.TimezoneMismatchField";
static props = {
...super.props,
tzOffsetField: { type: String, optional: true },
mismatchTitle: { type: String, optional: true },
};
static defaultProps = {
...super.defaultProps,
tzOffsetField: "tz_offset",
mismatchTitle: _t(
"Timezone Mismatch : This timezone is different from that of your browser.\nPlease, set the same timezone as your browser's to avoid time discrepancies in your system."
),
};
get mismatch() {
const userOffset = this.props.record.data[this.props.tzOffsetField];
if (userOffset && this.props.record.data[this.props.name]) {
const offset = -new Date().getTimezoneOffset();
let browserOffset = offset < 0 ? "-" : "+";
browserOffset += Math.floor(Math.abs(offset / 60))
.toFixed(0)
.padStart(2, "0");
browserOffset += Math.abs(offset % 60)
.toFixed(0)
.padStart(2, "0");
return browserOffset !== userOffset;
} else if (!this.props.record.data[this.props.name]) {
return true;
}
return false;
}
get mismatchTitle() {
if (!this.props.record.data[this.props.name]) {
return _t("Set a timezone on your user");
}
return this.props.mismatchTitle;
}
get options() {
if (!this.mismatch) {
return super.options;
}
return super.options.map((option) => {
const [value, label] = option;
if (value === this.props.record.data[this.props.name]) {
const offset = this.props.record.data[this.props.tzOffsetField].match(
/([+-])([0-9]{2})([0-9]{2})/
);
const sign = offset[1] === "-" ? -1 : 1;
const userOffset = sign * (parseInt(offset[2]) * 60 + parseInt(offset[3]));
const browserOffset = -new Date().getTimezoneOffset();
// UTC time of the user's selected timezone.
// E.g.
// - current time in UTC, say equal to 2021-01-01T00:00:00Z
// - userOffset of +0300 = 180 minutes
// - browserOffset of +0200 = -new Date().getTimezoneOffset() = 120 minutes
// - userUTCDatetime is then 2021-01-01T01:00:00Z
const userUTCDatetime = DateTime.utc().plus({
minutes: userOffset - browserOffset,
});
return [value, `${label} (${formatDateTime(userUTCDatetime)})`];
}
return [value, label];
});
}
}
export const timezoneMismatchField = {
...selectionField,
component: TimezoneMismatchField,
additionalClasses: ["d-flex"],
supportedOptions: [
...(selectionField.supportedOptions || []),
{
label: _t("Mismatch title"),
name: "mismatch_title",
type: "string",
},
{
label: _t("Timezone offset field"),
name: "tz_offset_field",
type: "field",
availableTypes: ["char"],
},
],
extractProps({ options }) {
const props = selectionField.extractProps(...arguments);
props.tzOffsetField = options.tz_offset_field;
props.mismatchTitle = options.mismatch_title;
return props;
},
};
registry.category("fields").add("timezone_mismatch", timezoneMismatchField);
Registry / API
- Registry name
timezoneMismatchField- Category
fields- Module
web- Slug
timezone-mismatch-field- Nav group
forms