Org Chart Widget with Modal

dagarson
Tera Guru

Hello I am trying to build a portal org chart widget with a popup modal. the idea is that when you click the menu next to the persons name.

dagarson_0-1747758520025.png

this widget will popup with the persons info

dagarson_1-1747758573130.png

I've been working on this for a while and just cant seem to find the problem. when I click the menu it just pops up like this

dagarson_2-1747758625837.png

Here is my code for the org chart widget

<div class="org-chart">
  <!-- Manager -->
  <div class="user-card manager-card">
    <div class="kebab-menu" ng-click="openMenu($event, data.user)">&#8942;</div>
    <div class="card-content">
      <div class="avatar-wrapper">
        <div ng-if="!data.user.photo" class="initials">{{getInitials(data.user.name)}}</div>
      </div>
      <div class="info">
        <div class="name">{{data.user.name}}</div>
        <div class="title">{{data.user.title}}</div>
      </div>
    </div>
  </div>

  <div class="line"></div>

  <!-- Reports -->
  <div class="reports-container">
    <div class="user-card report-card" ng-repeat="rep in data.reports">
      <div class="kebab-menu" ng-click="openMenu($event, rep)">&#8942;</div>
      <div class="card-content">
        <div class="avatar-wrapper">
          <div ng-if="!rep.photo" class="initials">{{getInitials(rep.name)}}</div>
        </div>
        <div class="info">
          <div class="name">{{rep.name}}</div>
          <div class="title">{{rep.title}}</div>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- Optional hidden instance -->
<div style="display: none;">
  <sp-widget widget="data.employeeDetailsWidget"></sp-widget>
</div>

 

//Client script 
function($scope, $uibModal) {
  $scope.getInitials = function(fullName) {
    if (!fullName) return '';
    let names = fullName.trim().split(' ');
    let initials = names[0].charAt(0);
    if (names.length > 1) {
      initials += names[names.length - 1].charAt(0);
    }
    return initials.toUpperCase();
  };

  $scope.openMenu = function(event, user) {
    event.stopPropagation();
console.log("Opening modal for user sys_id:", user.sys_id);

$scope.openMenu = function(event, user) {
  event.stopPropagation();

  $uibModal.open({
    size: 'lg',
    windowClass: 'employee-details-modal',
    template: `
      <div class="modal-header">
        <h4 class="modal-title">Employee Details</h4>
        <button type="button" class="close" ng-click="close()">×</button>
      </div>
      <div class="modal-body">
        <sp-widget widget="data.modalWidget"></sp-widget>
      </div>
    `,
    controller: function($scope, $uibModalInstance) {
      $scope.data = {
        modalWidget: {
          sys_id: 'a73327b683e56a104e1bc296feaad3e6', // Your widget sys_id
          options: {
            user_sys_id: user.sys_id
          }
        }
      };

      $scope.close = function() {
        $uibModalInstance.dismiss();
      };
    }
  });
};

  };
}

//Server Script
(function() {
  var currentUser = gs.getUserID();

  var userGR = new GlideRecord('sys_user');
  if (userGR.get(currentUser)) {
    data.user = {
      name: userGR.name.toString(),
      title: userGR.title.toString(),
      photo: userGR.photo ? userGR.photo.toString() : '',
      sys_id: userGR.getUniqueValue()
    };
  }

  data.reports = [];
  var repGR = new GlideRecord('sys_user');
  repGR.addQuery('manager', currentUser);
  repGR.query();
  while (repGR.next()) {
    data.reports.push({
      name: repGR.name.toString(),
      title: repGR.title.toString(),
      photo: repGR.photo ? repGR.photo.toString() : '',
      sys_id: repGR.getUniqueValue()
    });
  }

  // Optional: define hidden widget instance (unused, safe fallback)
  data.employeeDetailsWidget = {
    sys_id: 'e08f190a83a166104e1bc296feaad334',
    options: {
      user_sys_id: currentUser
    }
  };
})();

And the script for the modal widget

<div class="modal-header">
  <h4 class="modal-title">{{data.name}}</h4>
  <button type="button" class="close" ng-click="close()">×</button>
</div>

<div class="modal-body">
  <div class="employee-details">
    <div class="header-container">
      <div class="user-avatar">
        <img ng-if="data.profileImage" ng-src="{{data.profileImage}}" alt="User photo" />
        <div ng-if="!data.profileImage" class="avatar-initials">{{data.initials}}</div>
      </div>
      <div class="user-info">
        <h2 class="user-name">{{data.name}}</h2>
        <p class="user-title">{{data.title}}</p>
      </div>
    </div>

    <div class="contact-info">
      <div class="contact-item">
        <div class="contact-label"><span class="location-icon"></span> Location:</div>
        <div class="contact-value">{{data.location}}</div>
      </div>
      <div class="contact-item">
        <div class="contact-label">📧 Email:</div>
        <div class="contact-value">
          <a href="mailto:{{data.email}}">{{data.email}}</a>
        </div>
      </div>
      <div class="contact-item">
        <div class="contact-label">📞 Work phone:</div>
        <div class="contact-value">{{data.phone}}</div>
      </div>
    </div>
  </div>
</div>
//Server script
(function() {
  var userId;

  if (typeof input !== 'undefined' && input.options && input.options.user_sys_id) {
    userId = input.options.user_sys_id;
  } else if (typeof options !== 'undefined' && options.user_sys_id) {
    userId = options.user_sys_id;
  } else {
    userId = gs.getUserID(); // fallback to logged-in user
  }

  var userGR = new GlideRecord('sys_user');
  if (!userGR.get(userId)) {
    data.name = "Invalid user";
    return;
  }

  data.name = userGR.getDisplayValue();
  data.title = userGR.title + '';
  data.email = userGR.email + '';
  data.phone = userGR.phone + '';
  data.location = userGR.location ? userGR.location.getDisplayValue() : 'Not specified';

  var names = data.name.trim().split(' ');
  data.initials = names.length >= 2
    ? names[0].charAt(0) + names[names.length - 1].charAt(0)
    : data.name.substring(0, 2);
  data.initials = data.initials.toUpperCase();

  var photo = new GlideUser(userGR.sys_id.toString()).getPhoto();
  data.profileImage = (photo && photo.indexOf("photo.do") !== -1) ? photo : null;
})();

 

Any Assistance would be appreciated.

0 REPLIES 0