diff --git a/addons/hr/static/src/components/hr_presence_status/hr_presence_status.js b/addons/hr/static/src/components/hr_presence_status/hr_presence_status.js
new file mode 100644
index 00000000000..b409f128f66
--- /dev/null
+++ b/addons/hr/static/src/components/hr_presence_status/hr_presence_status.js
@@ -0,0 +1,77 @@
+/** @odoo-module */
+
+import { Component } from "@odoo/owl";
+
+import { _t } from "@web/core/l10n/translation";
+import { registry } from "@web/core/registry";
+import { standardFieldProps } from "@web/views/fields/standard_field_props";
+
+export class HrPresenceStatus extends Component {
+ static template = "hr.HrPresenceStatus";
+ static props = {
+ ...standardFieldProps,
+ tag: { type: String, optional: true },
+ };
+ static defaultProps = {
+ tag: "small",
+ };
+
+ get classNames() {
+ const classNames = ["fa"];
+ classNames.push(
+ `fa-${this.props.tag === "small" ? "fw" : "2x"}`,
+ this.icon,
+ "o_button_icon",
+ "hr_presence",
+ "align-middle",
+ this.color,
+ )
+ return classNames.join(" ");
+ }
+
+ get color() {
+ switch (this.value) {
+ case "presence_present":
+ case "presence_absent_active":
+ return "text-success";
+ case "presence_absent":
+ return "text-muted";
+ case "presence_to_define":
+ return "text-warning";
+ default:
+ return "";
+ }
+ }
+
+ get icon() {
+ return `fa-circle${this.value.startsWith("presence_absent") ? "-o" : ""}`;
+ }
+
+ get label() {
+ return this.value !== false
+ ? this.options.find(([value, label]) => value === this.value)[1]
+ : "";
+ }
+
+ get options() {
+ return this.props.record.fields[this.props.name].selection.filter(
+ (option) => option[0] !== false && option[1] !== ""
+ );
+ }
+
+ get value() {
+ return this.props.record.data[this.props.name];
+ }
+}
+
+export const hrPresenceStatus = {
+ component: HrPresenceStatus,
+ displayName: _t("HR Presence Status"),
+ extractProps({ viewType }, dynamicInfo) {
+ return {
+ tag: viewType === "kanban" ? "span" : "small",
+ };
+ },
+};
+
+registry.category("fields").add("hr_presence_status", hrPresenceStatus)
diff --git a/addons/hr/static/src/components/hr_presence_status/hr_presence_status.xml b/addons/hr/static/src/components/hr_presence_status/hr_presence_status.xml
new file mode 100644
index 00000000000..db69c3d542b
--- /dev/null
+++ b/addons/hr/static/src/components/hr_presence_status/hr_presence_status.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/addons/hr/views/hr_employee_public_views.xml b/addons/hr/views/hr_employee_public_views.xml
index 53d8d16bb38..9b06c5d1c95 100644
--- a/addons/hr/views/hr_employee_public_views.xml
+++ b/addons/hr/views/hr_employee_public_views.xml
@@ -147,31 +147,8 @@
- -
-
-
-
-
-
-
-
-
-
-
-
-
+ -
+
-
diff --git a/addons/hr/views/hr_employee_views.xml b/addons/hr/views/hr_employee_views.xml
index 0196033953b..e2dca6d8019 100644
--- a/addons/hr/views/hr_employee_views.xml
+++ b/addons/hr/views/hr_employee_views.xml
@@ -52,8 +52,6 @@
-
-
@@ -81,16 +79,7 @@
@@ -300,31 +289,8 @@
- -
-
-
-
-
-
-
-
-
-
-
-
-
+ -
+
-
diff --git a/addons/hr_holidays/static/src/components/hr_presence_status/hr_presence_status.js b/addons/hr_holidays/static/src/components/hr_presence_status/hr_presence_status.js
new file mode 100644
index 00000000000..ae4e86ef2ac
--- /dev/null
+++ b/addons/hr_holidays/static/src/components/hr_presence_status/hr_presence_status.js
@@ -0,0 +1,22 @@
+/** @odoo-module **/
+
+import { patch } from "@web/core/utils/patch";
+
+import { HrPresenceStatus } from "@hr/components/hr_presence_status/hr_presence_status";
+
+patch(HrPresenceStatus.prototype, {
+ get classNames() {
+ const classNames = super.classNames;
+ if (this.value.startsWith("presence_holiday")) {
+ return `${classNames} fa-plane`;
+ }
+ return classNames;
+ },
+
+ get color() {
+ if (this.value.startsWith("presence_holiday")) {
+ return `text-${this.value === "presence_holiday_present" ? "success" : "warning"}`;
+ }
+ return super.color;
+ },
+});
diff --git a/addons/hr_holidays/views/hr_views.xml b/addons/hr_holidays/views/hr_views.xml
index d928483343d..3d1801bc204 100644
--- a/addons/hr_holidays/views/hr_views.xml
+++ b/addons/hr_holidays/views/hr_views.xml
@@ -94,21 +94,6 @@
-
-
-
-
-
-
- On Time Off
-
-
@@ -124,23 +109,6 @@
-
-
-
-
-
-
-
-
-
@@ -151,14 +119,8 @@
-
- not last_activity or not user_id or not id
-
-
-
-
-
-
+
+ not last_activity or not id
diff --git a/addons/hr_homeworking/static/src/components/hr_presence_status/hr_presence_status.js b/addons/hr_homeworking/static/src/components/hr_presence_status/hr_presence_status.js
new file mode 100644
index 00000000000..ced6c43b08f
--- /dev/null
+++ b/addons/hr_homeworking/static/src/components/hr_presence_status/hr_presence_status.js
@@ -0,0 +1,65 @@
+/** @odoo-module **/
+
+import { _t } from "@web/core/l10n/translation";
+import { patch } from "@web/core/utils/patch";
+
+import { HrPresenceStatus, hrPresenceStatus } from "@hr/components/hr_presence_status/hr_presence_status";
+
+patch(HrPresenceStatus.prototype, {
+ get color() {
+ if (this.location) {
+ let color = "text-muted";
+ if (this.props.record.data.hr_presence_state !== "to_define") {
+ color = this.props.record.data.hr_presence_state === "present" ? "text-success" : "text-warning";
+ }
+ return color;
+ }
+ return super.color;
+ },
+
+ get icon() {
+ if (this.location) {
+ switch (this.location) {
+ case "home":
+ return "fa-home";
+ case "office":
+ return "fa-building";
+ case "other":
+ return "fa-map-marker";
+ }
+ }
+ return super.icon;
+ },
+
+ get label() {
+ if (this.location) {
+ return _t("Working from %s", this.location);
+ }
+ return super.label;
+ },
+
+ get location() {
+ let location = this.value?.split("_")[1] || "";
+ if (location && !['home', 'office', 'other'].includes(location)) {
+ location = "";
+ }
+ return location;
+ },
+});
+
+const additionalFieldDependencies = [
+ { name: "hr_presence_state", type: "selection" },
+];
+if (typeof hrPresenceStatus.fieldDependencies === "function") {
+ const oldFieldDependencies = hrPresenceStatus.fieldDependencies;
+ hrPresenceStatus.fieldDependencies = (widgetInfo) => {
+ const fieldDependencies = oldFieldDependencies(widgetInfo);
+ fieldDependencies.push(...additionalFieldDependencies);
+ return fieldDependencies;
+ }
+} else {
+ hrPresenceStatus.fieldDependencies = [
+ ...(hrPresenceStatus.fieldDependencies || []),
+ ...additionalFieldDependencies,
+ ];
+}
diff --git a/addons/hr_homeworking/views/hr_employee_views.xml b/addons/hr_homeworking/views/hr_employee_views.xml
index a950689bd0b..566caa5dfc1 100644
--- a/addons/hr_homeworking/views/hr_employee_views.xml
+++ b/addons/hr_homeworking/views/hr_employee_views.xml
@@ -53,45 +53,8 @@
hr.employee
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- hr.employee.kanban.inherit.homeworking
- hr.employee.public
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+