diff --git a/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js b/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js
index d93cc1c6a414..41837171a7ac 100644
--- a/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js
+++ b/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js
@@ -175,7 +175,7 @@ qx.Class.define("osparc.conversation.AddMessage", {
     addComment: function() {
       const conversationId = this.getConversationId();
       if (conversationId) {
-        this.__postMessage();
+        return this.__postMessage();
       } else {
         const studyData = this.getStudyData();
         let promise = null;
@@ -191,10 +191,10 @@ qx.Class.define("osparc.conversation.AddMessage", {
           }
           promise = osparc.store.ConversationsSupport.getInstance().postConversation(extraContext);
         }
-        promise
+        return promise
           .then(data => {
             this.setConversationId(data["conversationId"]);
-            this.__postMessage();
+            return this.__postMessage();
           });
       }
     },
@@ -211,12 +211,14 @@ qx.Class.define("osparc.conversation.AddMessage", {
         } else {
           promise = osparc.store.ConversationsSupport.getInstance().postMessage(conversationId, content);
         }
-        promise
+        return promise
           .then(data => {
             this.fireDataEvent("messageAdded", data);
             commentField.getChildControl("text-area").setValue("");
+            return data;
           });
       }
+      return Promise.reject();
     },
 
     __editComment: function() {
diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js
index 165437d17962..4b5c8181db9f 100644
--- a/services/static-webserver/client/source/class/osparc/data/Resources.js
+++ b/services/static-webserver/client/source/class/osparc/data/Resources.js
@@ -1515,7 +1515,7 @@ qx.Class.define("osparc.data.Resources", {
             method: "GET",
             url: statics.API + "/conversations/{conversationId}"
           },
-          renameConversation: {
+          patchConversation: {
             method: "PATCH",
             url: statics.API + "/conversations/{conversationId}"
           },
diff --git a/services/static-webserver/client/source/class/osparc/data/model/Conversation.js b/services/static-webserver/client/source/class/osparc/data/model/Conversation.js
index b1e0e568751a..01a322c0c974 100644
--- a/services/static-webserver/client/source/class/osparc/data/model/Conversation.js
+++ b/services/static-webserver/client/source/class/osparc/data/model/Conversation.js
@@ -246,6 +246,13 @@ qx.Class.define("osparc.data.model.Conversation", {
         });
     },
 
+    patchExtraContext: function(extraContext) {
+      osparc.store.ConversationsSupport.getInstance().patchExtraContext(this.getConversationId(), extraContext)
+        .then(() => {
+          this.setExtraContext(extraContext);
+        });
+    },
+
     addMessage: function(message) {
       if (message) {
         const found = this.__messages.find(msg => msg["messageId"] === message["messageId"]);
@@ -284,6 +291,27 @@ qx.Class.define("osparc.data.model.Conversation", {
         return this.getExtraContext()["projectId"];
       }
       return null;
-    }
+    },
+
+    getAppointment: function() {
+      if (this.getExtraContext() && "appointment" in this.getExtraContext()) {
+        return this.getExtraContext()["appointment"];
+      }
+      return null;
+    },
+
+    setAppointment: function(appointment) {
+      const extraContext = this.getExtraContext() || {};
+      extraContext["appointment"] = appointment ? appointment.toISOString() : null;
+      // OM: Supporters are not allowed to patch the conversation metadata yet
+      const backendAllowsPatch = osparc.store.Products.getInstance().amIASupportUser() ? false : true;
+      if (backendAllowsPatch) {
+        return osparc.store.ConversationsSupport.getInstance().patchExtraContext(this.getConversationId(), extraContext)
+          .then(() => {
+            this.setExtraContext(Object.assign({}, extraContext));
+        });
+      }
+      return Promise.resolve(this.setExtraContext(Object.assign({}, extraContext)));
+    },
   },
 });
diff --git a/services/static-webserver/client/source/class/osparc/store/ConversationsSupport.js b/services/static-webserver/client/source/class/osparc/store/ConversationsSupport.js
index 05b5cae55214..4aa7cd1361b4 100644
--- a/services/static-webserver/client/source/class/osparc/store/ConversationsSupport.js
+++ b/services/static-webserver/client/source/class/osparc/store/ConversationsSupport.js
@@ -124,7 +124,19 @@ qx.Class.define("osparc.store.ConversationsSupport", {
           name,
         }
       };
-      return osparc.data.Resources.fetch("conversationsSupport", "renameConversation", params);
+      return osparc.data.Resources.fetch("conversationsSupport", "patchConversation", params);
+    },
+
+    patchExtraContext: function(conversationId, extraContext) {
+      const params = {
+        url: {
+          conversationId,
+        },
+        data: {
+          extraContext,
+        }
+      };
+      return osparc.data.Resources.fetch("conversationsSupport", "patchConversation", params);
     },
 
     fetchLastMessage: function(conversationId) {
diff --git a/services/static-webserver/client/source/class/osparc/support/ConversationPage.js b/services/static-webserver/client/source/class/osparc/support/ConversationPage.js
index 685f7372ebc5..ed1eb3404598 100644
--- a/services/static-webserver/client/source/class/osparc/support/ConversationPage.js
+++ b/services/static-webserver/client/source/class/osparc/support/ConversationPage.js
@@ -84,14 +84,8 @@ qx.Class.define("osparc.support.ConversationPage", {
             });
           this.getChildControl("conversation-header-center-layout").addAt(control, 0);
           break;
-        case "conversation-extra-content":
-          control = new qx.ui.basic.Label().set({
-            font: "text-12",
-            textColor: "text-disabled",
-            rich: true,
-            allowGrowX: true,
-            selectable: true,
-          });
+        case "conversation-extra-layout":
+          control = new qx.ui.container.Composite(new qx.ui.layout.VBox(2));
           this.getChildControl("conversation-header-center-layout").addAt(control, 1);
           break;
         case "open-project-button":
@@ -105,6 +99,19 @@ qx.Class.define("osparc.support.ConversationPage", {
           control.addListener("execute", () => this.__openProjectDetails());
           this.getChildControl("conversation-header-layout").addAt(control, 2);
           break;
+        case "set-appointment-button": {
+          control = new qx.ui.form.Button().set({
+            maxWidth: 26,
+            maxHeight: 24,
+            padding: [0, 6],
+            alignX: "center",
+            alignY: "middle",
+            icon: "@FontAwesome5Solid/clock/12",
+          });
+          control.addListener("execute", () => this.__openAppointmentDetails());
+          this.getChildControl("conversation-header-layout").addAt(control, 3);
+          break;
+        }
         case "conversation-options": {
           control = new qx.ui.form.MenuButton().set({
             maxWidth: 24,
@@ -123,7 +130,7 @@ qx.Class.define("osparc.support.ConversationPage", {
           });
           renameButton.addListener("execute", () => this.__renameConversation());
           menu.add(renameButton);
-          this.getChildControl("conversation-header-layout").addAt(control, 3);
+          this.getChildControl("conversation-header-layout").addAt(control, 4);
           break;
         }
         case "conversation-content":
@@ -146,28 +153,65 @@ qx.Class.define("osparc.support.ConversationPage", {
         title.setValue(this.tr("Ask a Question"));
       }
 
-      const extraContextLabel = this.getChildControl("conversation-extra-content");
+      const extraContextLayout = this.getChildControl("conversation-extra-layout");
       const amISupporter = osparc.store.Products.getInstance().amIASupportUser();
-      if (conversation && amISupporter) {
-        const extraContext = conversation.getExtraContext();
-        if (extraContext && Object.keys(extraContext).length) {
-          let extraContextText = `Ticket ID: ${conversation.getConversationId()}`;
-          const contextProjectId = conversation.getContextProjectId();
-          if (contextProjectId) {
-            extraContextText += `
Project ID: ${contextProjectId}`;
+      if (conversation) {
+        const createExtraContextLabel = text => {
+          return new qx.ui.basic.Label(text).set({
+            font: "text-12",
+            textColor: "text-disabled",
+            rich: true,
+            allowGrowX: true,
+            selectable: true,
+          });
+        };
+        const updateExtraContext = () => {
+          extraContextLayout.removeAll();
+          const extraContext = conversation.getExtraContext();
+          if (extraContext && Object.keys(extraContext).length) {
+            const ticketIdLabel = createExtraContextLabel(`Ticket ID: ${conversation.getConversationId()}`);
+            extraContextLayout.add(ticketIdLabel);
+            const contextProjectId = conversation.getContextProjectId();
+            if (contextProjectId && amISupporter) {
+              const projectIdLabel = createExtraContextLabel(`Project ID: ${contextProjectId}`);
+              extraContextLayout.add(projectIdLabel);
+            }
+            const appointment = conversation.getAppointment();
+            if (appointment) {
+              const appointmentLabel = createExtraContextLabel();
+              let appointmentText = "Appointment: ";
+              if (appointment === "requested") {
+                // still pending
+                appointmentText += appointment;
+              } else {
+                // already set
+                appointmentText += osparc.utils.Utils.formatDateAndTime(new Date(appointment));
+                appointmentLabel.set({
+                  cursor: "pointer",
+                  toolTipText: osparc.utils.Utils.formatDateWithCityAndTZ(new Date(appointment)),
+                });
+              }
+              appointmentLabel.setValue(appointmentText);
+              extraContextLayout.add(appointmentLabel);
+            }
           }
-          extraContextLabel.setValue(extraContextText);
-        }
-        extraContextLabel.show();
-      } else {
-        extraContextLabel.exclude();
+        };
+        updateExtraContext();
+        conversation.addListener("changeExtraContext", () => updateExtraContext(), this);
       }
 
-      const openButton = this.getChildControl("open-project-button");
+      const openProjectButton = this.getChildControl("open-project-button");
       if (conversation && conversation.getContextProjectId()) {
-        openButton.show();
+        openProjectButton.show();
       } else {
-        openButton.exclude();
+        openProjectButton.exclude();
+      }
+
+      const setAppointmentButton = this.getChildControl("set-appointment-button");
+      if (conversation && conversation.getAppointment() && amISupporter) {
+        setAppointmentButton.show();
+      } else {
+        setAppointmentButton.exclude();
       }
 
       const options = this.getChildControl("conversation-options");
@@ -193,6 +237,17 @@ qx.Class.define("osparc.support.ConversationPage", {
       }
     },
 
+    __openAppointmentDetails: function() {
+      const win = new osparc.widget.DateTimeChooser();
+      win.addListener("dateChanged", e => {
+        const newValue = e.getData()["newValue"];
+        this.getConversation().setAppointment(newValue)
+          .catch(err => console.error(err));
+        win.close();
+      }, this);
+      win.open();
+    },
+
     __renameConversation: function() {
       let oldName = this.getConversation().getName();
       if (oldName === "null") {
@@ -207,5 +262,19 @@ qx.Class.define("osparc.support.ConversationPage", {
       renamer.center();
       renamer.open();
     },
+
+    __getAddMessageField: function() {
+      return this.getChildControl("conversation-content") &&
+        this.getChildControl("conversation-content").getChildControl("add-message");
+    },
+
+    postMessage: function(message) {
+      const addMessage = this.__getAddMessageField();
+      if (addMessage && addMessage.getChildControl("comment-field")) {
+        addMessage.getChildControl("comment-field").setText(message);
+        return addMessage.addComment();
+      }
+      return Promise.reject();
+    },
   }
 });
diff --git a/services/static-webserver/client/source/class/osparc/support/SupportCenter.js b/services/static-webserver/client/source/class/osparc/support/SupportCenter.js
index 925b5e9cb327..80ae521f7c27 100644
--- a/services/static-webserver/client/source/class/osparc/support/SupportCenter.js
+++ b/services/static-webserver/client/source/class/osparc/support/SupportCenter.js
@@ -38,10 +38,12 @@ qx.Class.define("osparc.support.SupportCenter", {
     this.getChildControl("conversations-intro-text");
     this.getChildControl("conversations-list");
     this.getChildControl("ask-a-question-button");
+    this.getChildControl("book-a-call-button");
   },
 
   statics: {
     WINDOW_WIDTH: 430,
+    REQUEST_CALL_MESSAGE: "Dear Support,\nI would like to make an appointment for a support call.",
 
     getMaxHeight: function() {
       // height: max 80% of screen, or 600px
@@ -112,15 +114,29 @@ qx.Class.define("osparc.support.SupportCenter", {
           });
           break;
         }
+        case "buttons-layout":
+          control = new qx.ui.container.Composite(new qx.ui.layout.HBox(10).set({
+            alignX: "center",
+          }));
+          this.getChildControl("conversations-layout").add(control);
+          break;
         case "ask-a-question-button":
           control = new osparc.ui.form.FetchButton(this.tr("Ask a Question")).set({
             appearance: "strong-button",
             allowGrowX: false,
             center: true,
-            alignX: "center",
           });
           control.addListener("execute", () => this.openConversation(null), this);
-          this.getChildControl("conversations-layout").add(control);
+          this.getChildControl("buttons-layout").add(control);
+          break;
+        case "book-a-call-button":
+          control = new osparc.ui.form.FetchButton(this.tr("Book a Call")).set({
+            appearance: "strong-button",
+            allowGrowX: false,
+            center: true,
+          });
+          control.addListener("execute", () => this.createConversationBookCall(null), this);
+          this.getChildControl("buttons-layout").add(control);
           break;
         case "conversation-page":
           control = new osparc.support.ConversationPage();
@@ -152,5 +168,30 @@ qx.Class.define("osparc.support.SupportCenter", {
         this.__showConversation();
       }
     },
+
+    createConversationBookCall: function() {
+      const conversationPage = this.getChildControl("conversation-page");
+      conversationPage.setConversation(null);
+      this.__showConversation();
+      conversationPage.postMessage(osparc.support.SupportCenter.REQUEST_CALL_MESSAGE)
+        .then(data => {
+          const conversationId = data["conversationId"];
+          osparc.store.ConversationsSupport.getInstance().getConversation(conversationId)
+            .then(conversation => {
+              // update conversation name and patch extra_context
+              conversation.renameConversation("Book a call");
+              conversation.patchExtraContext({
+                ...conversation.getExtraContext(),
+                "appointment": "requested"
+              });
+              // This should be an automatic response in the chat
+              const msg = this.tr("Your request has been sent.
Our support team will get back to you.");
+              osparc.FlashMessenger.logAs(msg, "INFO");
+            });
+        })
+        .catch(err => {
+          console.error("Error sending request call message", err);
+        });
+    },
   }
 });
diff --git a/services/static-webserver/client/source/class/osparc/ui/form/DateTimeField.js b/services/static-webserver/client/source/class/osparc/ui/form/DateTimeField.js
new file mode 100644
index 000000000000..300a6d212b9e
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/ui/form/DateTimeField.js
@@ -0,0 +1,134 @@
+/* ************************************************************************
+
+   osparc - the simcore frontend
+
+   https://osparc.io
+
+   Copyright:
+     2025 IT'IS Foundation, https://itis.swiss
+
+   License:
+     MIT: https://opensource.org/licenses/MIT
+
+   Authors:
+     * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+qx.Class.define("osparc.ui.form.DateTimeField", {
+  extend: qx.ui.core.Widget,
+  include: [qx.ui.form.MForm],
+  implement: [qx.ui.form.IForm, qx.ui.form.IStringForm],
+
+  construct: function() {
+    this.base(arguments);
+
+    this._setLayout(new qx.ui.layout.HBox(5));
+
+    this.set({
+      maxHeight: 26
+    });
+
+    // Date selector
+    this.__dateField = new qx.ui.form.DateField();
+    const dateFormat = new qx.util.format.DateFormat("dd/MM/yyyy");
+    this.__dateField.setDateFormat(dateFormat);
+    this._add(this.__dateField);
+
+    // Hour selector
+    this.__hourSpinner = new qx.ui.form.Spinner(0, 12, 23);
+    this._add(this.__hourSpinner);
+
+    // Minute selector
+    this.__minuteSpinner = new qx.ui.form.Spinner(0, 0, 59);
+    this._add(this.__minuteSpinner);
+
+    const now = new Date();
+    this.setValue(now);
+
+    // Sync changes back to value
+    this.__dateField.addListener("changeValue", this.__updateValue, this);
+    this.__hourSpinner.addListener("changeValue", this.__updateValue, this);
+    this.__minuteSpinner.addListener("changeValue", this.__updateValue, this);
+  },
+
+  properties: {
+    // The combined Date value
+    value: {
+      check: "Date",
+      nullable: true,
+      event: "changeValue",
+      apply: "_applyValue"
+    }
+  },
+
+  members: {
+    __dateField: null,
+    __hourSpinner: null,
+    __minuteSpinner: null,
+
+    _applyValue: function(value, old) {
+      if (value) {
+        this.__dateField.setValue(value);
+        this.__hourSpinner.setValue(value.getHours());
+        this.__minuteSpinner.setValue(value.getMinutes());
+      } else {
+        this.__dateField.resetValue();
+        this.__hourSpinner.resetValue();
+        this.__minuteSpinner.resetValue();
+      }
+    },
+
+    __updateValue: function() {
+      const date = this.__dateField.getValue();
+      const now = new Date();
+
+      if (date) {
+        // Prevent past dates
+        if (date < now.setHours(0,0,0,0)) {
+          this.__dateField.setValue(new Date());
+          return;
+        }
+
+        const newDate = new Date(date.getTime());
+        newDate.setHours(this.__hourSpinner.getValue());
+        newDate.setMinutes(this.__minuteSpinner.getValue());
+
+        // If today, prevent past time
+        const isToday =
+          date.getFullYear() === now.getFullYear() &&
+          date.getMonth() === now.getMonth() &&
+          date.getDate() === now.getDate();
+
+        if (isToday && newDate < now) {
+          this.__hourSpinner.setValue(now.getHours());
+          this.__minuteSpinner.setValue(now.getMinutes());
+          this.setValue(now);
+        } else {
+          this.setValue(newDate);
+        }
+      } else {
+        this.resetValue();
+      }
+    },
+
+    // Interface methods (IStringForm)
+    setValueAsString: function(str) {
+      const d = new Date(str);
+      if (!isNaN(d.getTime())) {
+        this.setValue(d);
+      }
+    },
+
+    getValueAsString: function() {
+      const v = this.getValue();
+      return v ? v.toISOString() : "";
+    }
+  },
+
+  destruct: function() {
+    this.__dateField = null;
+    this.__hourSpinner = null;
+    this.__minuteSpinner = null;
+  }
+});
diff --git a/services/static-webserver/client/source/class/osparc/ui/form/IntlTelInput.js b/services/static-webserver/client/source/class/osparc/ui/form/IntlTelInput.js
index 621c0583561f..d4519ff9e1be 100644
--- a/services/static-webserver/client/source/class/osparc/ui/form/IntlTelInput.js
+++ b/services/static-webserver/client/source/class/osparc/ui/form/IntlTelInput.js
@@ -5,7 +5,7 @@
    https://osparc.io
 
    Copyright:
-     2022 IT'IS Foundation, https://itis.swiss
+     2025 IT'IS Foundation, https://itis.swiss
 
    License:
      MIT: https://opensource.org/licenses/MIT
diff --git a/services/static-webserver/client/source/class/osparc/ui/message/FlashMessageOEC.js b/services/static-webserver/client/source/class/osparc/ui/message/FlashMessageOEC.js
index a2227e9274d0..30d59bb878ff 100644
--- a/services/static-webserver/client/source/class/osparc/ui/message/FlashMessageOEC.js
+++ b/services/static-webserver/client/source/class/osparc/ui/message/FlashMessageOEC.js
@@ -117,14 +117,8 @@ qx.Class.define("osparc.ui.message.FlashMessageOEC", {
       supportCenter.openConversation(null);
 
       const textToAddMessageField = msg => {
-        if (
-          supportCenter.getChildControl("conversation-page") &&
-          supportCenter.getChildControl("conversation-page").getChildControl("conversation-content") &&
-          supportCenter.getChildControl("conversation-page").getChildControl("conversation-content").getChildControl("add-message") &&
-          supportCenter.getChildControl("conversation-page").getChildControl("conversation-content").getChildControl("add-message").getChildControl("comment-field")
-        ) {
-          supportCenter.getChildControl("conversation-page").getChildControl("conversation-content").getChildControl("add-message").getChildControl("comment-field").setText(msg);
-          supportCenter.getChildControl("conversation-page").getChildControl("conversation-content").getChildControl("add-message").addComment();
+        if (supportCenter.getChildControl("conversation-page")) {
+          supportCenter.getChildControl("conversation-page").postMessage(msg);
         }
       }
 
@@ -149,6 +143,9 @@ qx.Class.define("osparc.ui.message.FlashMessageOEC", {
           const friendlyContext = this.__getSupportFriendlyContext();
           const text = "Dear Support Team,\n" + extraContext + "\n" + friendlyContext;
           textToAddMessageField(text);
+          // This should be an automatic response in the chat
+          const msg = this.tr("Thanks, your report has been sent.
Our support team will get back to you.");
+          osparc.FlashMessenger.logAs(msg, "INFO");
         } else {
           supportCenter.close();
         }
diff --git a/services/static-webserver/client/source/class/osparc/utils/Utils.js b/services/static-webserver/client/source/class/osparc/utils/Utils.js
index 905260ac17c3..471c076c542a 100644
--- a/services/static-webserver/client/source/class/osparc/utils/Utils.js
+++ b/services/static-webserver/client/source/class/osparc/utils/Utils.js
@@ -577,9 +577,9 @@ qx.Class.define("osparc.utils.Utils", {
     },
 
     /**
-      * @param value {Date Object} Date Object
+      * @param date {Date Object} Date Object
       */
-    formatDate: function(value) {
+    formatDate: function(date) {
       // create a date format like "Oct. 19, 11:31 AM" if it's this year
       const dateFormat = new qx.util.format.DateFormat(
         qx.locale.Date.getDateFormat("medium")
@@ -592,20 +592,20 @@ qx.Class.define("osparc.utils.Utils", {
       const tomorrow = new Date();
       tomorrow.setDate(tomorrow.getDate() + 1);
 
-      if (today.toDateString() === value.toDateString()) {
+      if (today.toDateString() === date.toDateString()) {
         dateStr = qx.locale.Manager.tr("Today");
-      } else if (yesterday.toDateString() === value.toDateString()) {
+      } else if (yesterday.toDateString() === date.toDateString()) {
         dateStr = qx.locale.Manager.tr("Yesterday");
-      } else if (tomorrow.toDateString() === value.toDateString()) {
+      } else if (tomorrow.toDateString() === date.toDateString()) {
         dateStr = qx.locale.Manager.tr("Tomorrow");
       } else {
         const currentYear = today.getFullYear();
-        if (value.getFullYear() === currentYear) {
+        if (date.getFullYear() === currentYear) {
           // Remove the year if it's the current year
           const shortDateFormat = new qx.util.format.DateFormat("MMM d");
-          dateStr = shortDateFormat.format(value);
+          dateStr = shortDateFormat.format(date);
         } else {
-          dateStr = dateFormat.format(value);
+          dateStr = dateFormat.format(date);
         }
       }
       return dateStr;
@@ -618,21 +618,54 @@ qx.Class.define("osparc.utils.Utils", {
     },
 
     /**
-      * @param value {Date Object} Date Object
+      * @param date {Date Object} Date Object
       */
-    formatTime: function(value, long = false) {
+    formatTime: function(date, long = false) {
       const timeFormat = new qx.util.format.DateFormat(
         qx.locale.Date.getTimeFormat(long ? "long" : "short")
       );
-      const timeStr = timeFormat.format(value);
+      const timeStr = timeFormat.format(date);
       return timeStr;
     },
 
     /**
-      * @param value {Date Object} Date Object
+      * @param date {Date Object} Date Object
       */
-    formatDateAndTime: function(value) {
-      return osparc.utils.Utils.formatDate(value) + " " + osparc.utils.Utils.formatTime(value);
+    formatDateAndTime: function(date) {
+      return osparc.utils.Utils.formatDate(date) + " " + osparc.utils.Utils.formatTime(date);
+    },
+
+    /**
+     * @param {Date} date - The date to format.
+     * @returns {String} - The formatted date string with city name and timezone. Sep 4, 1986, 17:00 Zurich (GMT+02:00)
+     */
+    formatDateWithCityAndTZ: function(date) {
+      // Short date/time formatter
+      const options = {
+        year: "numeric",   // 1986
+        month: "short",    // Sep
+        day: "numeric",    // 4
+        hour: "numeric",   // 9
+        minute: "2-digit",
+        hour12: false,     // 24h format
+      };
+
+      const dtf = new Intl.DateTimeFormat("en-US", options);
+      const formatted = dtf.format(date);
+
+      // Timezone city
+      const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
+      const city = tz.split("/").pop().replace("_", " ");
+
+      // UTC offset (minutes → +HH:MM)
+      const offsetMinutes = -date.getTimezoneOffset(); // JS returns opposite sign
+      const sign = offsetMinutes >= 0 ? "+" : "-";
+      const absMinutes = Math.abs(offsetMinutes);
+      const hours = String(Math.floor(absMinutes / 60)).padStart(2, "0");
+      const minutes = String(absMinutes % 60).padStart(2, "0");
+      const offsetStr = `GMT${sign}${hours}:${minutes}`;
+
+      return `${formatted} ${city} (${offsetStr})`;
     },
 
     formatMsToHHMMSS: function(ms) {
diff --git a/services/static-webserver/client/source/class/osparc/widget/DateTimeChooser.js b/services/static-webserver/client/source/class/osparc/widget/DateTimeChooser.js
new file mode 100644
index 000000000000..ac5b86607572
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/widget/DateTimeChooser.js
@@ -0,0 +1,111 @@
+/* ************************************************************************
+
+   osparc - the simcore frontend
+
+   https://osparc.io
+
+   Copyright:
+     2025 IT'IS Foundation, https://itis.swiss
+
+   License:
+     MIT: https://opensource.org/licenses/MIT
+
+   Authors:
+     * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+
+qx.Class.define("osparc.widget.DateTimeChooser", {
+  extend: osparc.ui.window.Window,
+
+  construct: function(winTitle, value) {
+    this.base(arguments, winTitle || this.tr("Choose a Date and Time"));
+
+    const width = 260;
+    const height = 26;
+    this.set({
+      layout: new qx.ui.layout.VBox(10),
+      autoDestroy: true,
+      modal: true,
+      width,
+      height,
+      showMaximize: false,
+      showMinimize: false,
+      showClose: true,
+      resizable: false,
+      clickAwayClose: false,
+    });
+
+    const dateTimeField = this.getChildControl("date-time-field");
+    if (value) {
+      dateTimeField.setValue(value);
+    }
+    this.getChildControl("cancel-button");
+    this.getChildControl("save-button");
+
+    this.center();
+
+    this.__attachEventHandlers();
+  },
+
+  events: {
+    "dateChanged": "qx.event.type.Data",
+  },
+
+  members: {
+    _createChildControlImpl: function(id) {
+      let control;
+      switch (id) {
+        case "date-time-field":
+          control = new osparc.ui.form.DateTimeField();
+          this.add(control);
+          break;
+        case "buttons-layout":
+          control = new qx.ui.container.Composite(new qx.ui.layout.HBox(5).set({
+            alignX: "right"
+          }));
+          this.add(control);
+          break;
+        case "cancel-button":
+          control = new qx.ui.form.Button(this.tr("Cancel")).set({
+            appearance: "form-button-text",
+          });
+          control.addListener("execute", () => this.close(), this);
+          this.getChildControl("buttons-layout").add(control);
+          break;
+        case "save-button": {
+          control = new qx.ui.form.Button(this.tr("Save")).set({
+            appearance: "form-button",
+          });
+          control.addListener("execute", e => {
+            const dateTimeField = this.getChildControl("date-time-field");
+            const data = {
+              newValue: dateTimeField.getValue()
+            };
+            this.fireDataEvent("dateChanged", data);
+          }, this);
+          this.getChildControl("buttons-layout").add(control);
+          break;
+        }
+      }
+      return control || this.base(arguments, id);
+    },
+
+    __attachEventHandlers: function() {
+      let command = new qx.ui.command.Command("Enter");
+      command.addListener("execute", () => {
+        this.getChildControl("save-button").execute();
+        command.dispose();
+        command = null;
+      });
+
+      let commandEsc = new qx.ui.command.Command("Esc");
+      commandEsc.addListener("execute", () => {
+        this.close();
+        commandEsc.dispose();
+        commandEsc = null;
+      });
+    }
+  }
+});