/*
* Copyright (c) 2009-2011 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.web.client.ui.pages.profile;
import org.eurekastreams.commons.client.ActionProcessor;
import org.eurekastreams.server.action.request.profile.GetFollowersFollowingRequest;
import org.eurekastreams.server.domain.EntityType;
import org.eurekastreams.server.domain.Page;
import org.eurekastreams.server.domain.stream.StreamScope;
import org.eurekastreams.server.domain.stream.StreamScope.ScopeType;
import org.eurekastreams.server.search.modelview.PersonModelView;
import org.eurekastreams.web.client.events.EventBus;
import org.eurekastreams.web.client.events.Observer;
import org.eurekastreams.web.client.events.SetBannerEvent;
import org.eurekastreams.web.client.events.StreamRequestEvent;
import org.eurekastreams.web.client.events.data.BaseDataResponseEvent;
import org.eurekastreams.web.client.events.data.DeletedPersonFollowersResponseEvent;
import org.eurekastreams.web.client.events.data.GotPersonFollowersResponseEvent;
import org.eurekastreams.web.client.events.data.GotPersonFollowingResponseEvent;
import org.eurekastreams.web.client.events.data.GotPersonJoinedGroupsResponseEvent;
import org.eurekastreams.web.client.events.data.GotPersonalBiographyResponseEvent;
import org.eurekastreams.web.client.events.data.GotPersonalEducationResponseEvent;
import org.eurekastreams.web.client.events.data.GotPersonalEmploymentResponseEvent;
import org.eurekastreams.web.client.events.data.GotPersonalInformationResponseEvent;
import org.eurekastreams.web.client.events.data.InsertedPersonFollowerResponseEvent;
import org.eurekastreams.web.client.history.CreateUrlRequest;
import org.eurekastreams.web.client.model.AllPopularHashTagsModel;
import org.eurekastreams.web.client.model.OrganizationModel;
import org.eurekastreams.web.client.model.PersonFollowersModel;
import org.eurekastreams.web.client.model.PersonFollowingModel;
import org.eurekastreams.web.client.model.PersonJoinedGroupsModel;
import org.eurekastreams.web.client.model.PersonalBiographyModel;
import org.eurekastreams.web.client.model.PersonalEducationModel;
import org.eurekastreams.web.client.model.PersonalEmploymentModel;
import org.eurekastreams.web.client.model.PersonalInformationModel;
import org.eurekastreams.web.client.ui.Session;
import org.eurekastreams.web.client.ui.common.LeftBarPanel;
import org.eurekastreams.web.client.ui.common.pagedlist.GroupRenderer;
import org.eurekastreams.web.client.ui.common.pagedlist.PagedListPanel;
import org.eurekastreams.web.client.ui.common.pagedlist.PersonRenderer;
import org.eurekastreams.web.client.ui.common.stream.StreamJsonRequestFactory;
import org.eurekastreams.web.client.ui.common.stream.StreamPanel;
import org.eurekastreams.web.client.ui.common.stream.renderers.ShowRecipient;
import org.eurekastreams.web.client.ui.common.tabs.SimpleTab;
import org.eurekastreams.web.client.ui.common.tabs.TabContainerPanel;
import org.eurekastreams.web.client.ui.pages.master.StaticResourceBundle;
import org.eurekastreams.web.client.ui.pages.profile.tabs.PersonalProfileAboutTabPanel;
import org.eurekastreams.web.client.ui.pages.profile.widgets.AboutPanel;
import org.eurekastreams.web.client.ui.pages.profile.widgets.BreadcrumbPanel;
import org.eurekastreams.web.client.ui.pages.profile.widgets.ChecklistProgressBarPanel;
import org.eurekastreams.web.client.ui.pages.profile.widgets.ConnectionsPanel;
import org.eurekastreams.web.client.ui.pages.profile.widgets.ContactInfoPanel;
import org.eurekastreams.web.client.ui.pages.profile.widgets.PopularHashtagsPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
/**
* Displays a summary of a person's profile.
*/
public class PersonalProfilePanel extends FlowPanel
{
/**
* Spacing panel -- we use floats in on the ProfilePage, so make sure nothing below it intrudes.
*/
SimplePanel clearPanel = new SimplePanel();
/**
* About panel.
*/
private final AboutPanel about;
/**
* Gets current user in session.
*/
private final PersonModelView currentUser = Session.getInstance().getCurrentPerson();
/**
* Holds the PortalPage section of the profile display.
*/
private TabContainerPanel portalPage = null;
/**
* Panel that shows the bread crumb navigation.
*/
private final BreadcrumbPanel breadCrumbPanel;
/**
* Link to go to the profile settings page.
*/
private final Hyperlink profileSettingsLink;
/**
* Panel that holds the tabbed portion of the profile display.
*/
private final FlowPanel portalPageContainer = new FlowPanel();
/**
* Left bar container.
*/
private final FlowPanel leftBarContainer = new FlowPanel();
/**
* panel that holds the profile summary.
*/
private final LeftBarPanel leftBarPanel = new LeftBarPanel();
/**
* The person whose profile we're looking at.
*/
private PersonModelView personModelView;
/**
* Followers.
*/
private int followers;
/**
* The panel that shows the checklist.
*/
private final ChecklistProgressBarPanel checklistPanel = new ChecklistProgressBarPanel(
"Employee Profile Checklist",
"Completing your profile is easy: upload your picture, enter your contact information, "
+ "and add some work and personal related information. Employees that fill "
+ "out their profile are more likely to be found by others across your organization.",
new CreateUrlRequest(Page.PERSONAL_SETTINGS, Session.getInstance().getCurrentPerson().getAccountId()));
/**
* The divider separating the checklistPanel from the rest of the left-bar content.
*/
private final FlowPanel checklistDivider = new FlowPanel();
/**
* Connections Panel Holds the Small boxes with the connect counts.
*/
private ConnectionsPanel connectionsPanel;
/**
* Constructor.
*
* @param accountId
* the account id.
*/
public PersonalProfilePanel(final String accountId)
{
profileSettingsLink = new Hyperlink("Configure", Session.getInstance().generateUrl(
new CreateUrlRequest(Page.PERSONAL_SETTINGS, accountId)));
RootPanel.get().addStyleName(StaticResourceBundle.INSTANCE.coreCss().profile());
ActionProcessor inProcessor = Session.getInstance().getActionProcessor();
inProcessor.setQueueRequests(true);
about = new AboutPanel(accountId);
portalPageContainer.addStyleName(StaticResourceBundle.INSTANCE.coreCss().profilePageContainer());
profileSettingsLink.addStyleName(StaticResourceBundle.INSTANCE.coreCss().configureTab());
profileSettingsLink.addStyleName(StaticResourceBundle.INSTANCE.coreCss().hidden());
leftBarContainer.addStyleName(StaticResourceBundle.INSTANCE.coreCss().leftBarContainer());
breadCrumbPanel = new BreadcrumbPanel(inProcessor);
this.add(breadCrumbPanel);
this.add(profileSettingsLink);
leftBarContainer.add(leftBarPanel);
this.add(leftBarContainer);
this.add(portalPageContainer);
this.add(clearPanel);
this.addStyleName(StaticResourceBundle.INSTANCE.coreCss().profilePage());
EventBus.getInstance().addObserver(GotPersonalInformationResponseEvent.class,
new Observer<GotPersonalInformationResponseEvent>()
{
public void update(final GotPersonalInformationResponseEvent event)
{
// Note: Must remove observer BEFORE building the widgets. The personal about tab widget makes
// the same request to the model as is being processed here. Unless the observer is unwired
// first, it will be called a second time.
EventBus.getInstance().removeObserver(GotPersonalInformationResponseEvent.class, this);
setEntity(event.getResponse());
}
});
PersonalInformationModel.getInstance().fetch(accountId, false);
AllPopularHashTagsModel.getInstance().fetch(null, true);
inProcessor.fireQueuedRequests();
}
/**
* We have the Person, so set up the Profile summary.
*
* @param inPerson
* the person whose profile is being displayed
*/
public void setEntity(final PersonModelView inPerson)
{
ActionProcessor inProcessor = Session.getInstance().getActionProcessor();
inProcessor.setQueueRequests(true);
if (inPerson == null)
{
showInvalidPersonMessage();
}
personModelView = inPerson;
leftBarPanel.clear();
portalPageContainer.clear();
// Set the banner.
Session.getInstance().getEventBus().notifyObservers(new SetBannerEvent(inPerson));
if (personModelView.getAccountId().equals(Session.getInstance().getCurrentPerson().getAccountId()))
{
profileSettingsLink.removeStyleName(StaticResourceBundle.INSTANCE.coreCss().hidden());
RootPanel.get().addStyleName(StaticResourceBundle.INSTANCE.coreCss().authenticated());
}
breadCrumbPanel.setPerson(personModelView);
followers = personModelView.getFollowersCount();
// Update the Profile summary
about.setPerson(personModelView);
connectionsPanel = new ConnectionsPanel();
connectionsPanel.addConnection("Followers", null, personModelView.getFollowersCount());
connectionsPanel.addConnection("Following", null, personModelView.getFollowingCount(),
StaticResourceBundle.INSTANCE.coreCss().center());
connectionsPanel.addConnection("Groups", null, personModelView.getGroupsCount());
Session.getInstance().getEventBus().addObserver(InsertedPersonFollowerResponseEvent.class,
new Observer<InsertedPersonFollowerResponseEvent>()
{
public void update(final InsertedPersonFollowerResponseEvent event)
{
followers++;
connectionsPanel.updateCount("Followers", followers);
}
});
Session.getInstance().getEventBus().addObserver(DeletedPersonFollowersResponseEvent.class,
new Observer<DeletedPersonFollowersResponseEvent>()
{
public void update(final DeletedPersonFollowersResponseEvent event)
{
followers--;
connectionsPanel.updateCount("Followers", followers);
}
});
// Make the Connections Tab
final PagedListPanel connectionTabContent = createConnectionsTabContent(personModelView);
// update the list of members after joining/leaving the group
Observer<BaseDataResponseEvent<Integer>> followChangeObserver = new Observer<BaseDataResponseEvent<Integer>>()
{
@SuppressWarnings("unchecked")
public void update(final BaseDataResponseEvent ev)
{
if ("Followers".equals(connectionTabContent.getCurrentFilter()))
{
connectionTabContent.refreshData();
}
}
};
Session.getInstance().getEventBus()
.addObserver(InsertedPersonFollowerResponseEvent.class, followChangeObserver);
Session.getInstance().getEventBus()
.addObserver(DeletedPersonFollowersResponseEvent.class, followChangeObserver);
leftBarPanel.addChildWidget(about);
leftBarPanel.addChildWidget(new PopularHashtagsPanel(ScopeType.PERSON, personModelView.getAccountId()));
leftBarPanel.addChildWidget(connectionsPanel);
leftBarPanel.addChildWidget(new ContactInfoPanel(personModelView));
if (personModelView.getAccountId().equals(Session.getInstance().getCurrentPerson().getAccountId()))
{
setUpChecklist();
}
final StreamPanel streamContent = new StreamPanel(ShowRecipient.FOREIGN_ONLY);
streamContent.setStreamScope(new StreamScope(ScopeType.PERSON, personModelView.getAccountId(), personModelView
.getStreamId()), (personModelView.isStreamPostable() || (currentUser.getAccountId() == personModelView
.getAccountId())));
if (personModelView.isAccountLocked())
{
streamContent.setLockedMessagePanel(generateLockedUserMessage());
}
String jsonRequest = StreamJsonRequestFactory.addRecipient(EntityType.PERSON, personModelView.getAccountId(),
StreamJsonRequestFactory.getEmptyRequest()).toString();
EventBus.getInstance().notifyObservers(new StreamRequestEvent(personModelView.getDisplayName(), jsonRequest));
portalPage = new TabContainerPanel();
portalPage.addTab(new SimpleTab("Stream", streamContent));
portalPage.addTab(new SimpleTab("Connections", connectionTabContent));
portalPage.addTab(new SimpleTab("About", new PersonalProfileAboutTabPanel(personModelView)));
portalPage.init();
portalPage.setStyleName(StaticResourceBundle.INSTANCE.coreCss().profileGadgetsContainer());
portalPageContainer.add(portalPage);
inProcessor.setQueueRequests(false);
inProcessor.fireQueuedRequests();
}
/**
* Generates a panel to use as the message when a user is locked out of the system.
*
* @return the Panel content containing the locked message.
*/
private Panel generateLockedUserMessage()
{
Panel errorReport = new FlowPanel();
errorReport.addStyleName(StaticResourceBundle.INSTANCE.coreCss().errorReport());
FlowPanel centeringPanel = new FlowPanel();
centeringPanel.addStyleName(StaticResourceBundle.INSTANCE.coreCss().errorReportContainer());
centeringPanel.add(errorReport);
add(centeringPanel);
FlowPanel msgPanel = new FlowPanel();
Label msgHeader = new Label("Employee no longer has access to Eureka Streams");
msgHeader.addStyleName(StaticResourceBundle.INSTANCE.coreCss().errorMessage());
Label msgText = new Label("This employee no longer has access to Eureka Streams. This could be due to a change"
+ " of assignment within the company or due to leaving the company.");
FlowPanel text = new FlowPanel();
text.add(msgText);
text.addStyleName(StaticResourceBundle.INSTANCE.coreCss().errorMessageText());
msgPanel.add(msgHeader);
msgPanel.add(msgText);
errorReport.add(msgPanel);
return errorReport;
}
/**
* Tell the user that the person does not exist.
*/
private void showInvalidPersonMessage()
{
OrganizationModel.getInstance().fetch("", true);
clear();
Panel errorReport = addNewCenteredErrorBox();
FlowPanel msgPanel = new FlowPanel();
Label msgHeader = new Label("Profile not found");
msgHeader.addStyleName(StaticResourceBundle.INSTANCE.coreCss().warningMessage());
Hyperlink directoryLink = new Hyperlink("profiles", Session.getInstance().generateUrl(
new CreateUrlRequest(Page.ORGANIZATIONS, "")));
Label msgText1 = new Label("The person you were looking for could not be found. Try browsing the ");
Label msgText2 = new Label(
" or searching the profiles by entering the name in the \"search profiles\" box above.");
FlowPanel msgText = new FlowPanel();
msgText.add(msgText1);
msgText.add(directoryLink);
msgText.add(msgText2);
msgText.addStyleName(StaticResourceBundle.INSTANCE.coreCss().errorMessageText());
msgPanel.add(msgHeader);
msgPanel.add(msgText);
errorReport.add(msgPanel);
}
/**
* Creates a new error report box and centers it on the page.
*
* @return The error report box, ready to have content added to it.
*/
private Panel addNewCenteredErrorBox()
{
// create panel
Panel errorReport = new FlowPanel();
errorReport.addStyleName(StaticResourceBundle.INSTANCE.coreCss().warningReport());
// center on page
FlowPanel centeringPanel = new FlowPanel();
centeringPanel.addStyleName(StaticResourceBundle.INSTANCE.coreCss().warningReportContainer());
centeringPanel.add(errorReport);
add(centeringPanel);
return errorReport;
}
/**
* Set up the checklist.
*/
private void setUpChecklist()
{
checklistDivider.addStyleName(StaticResourceBundle.INSTANCE.coreCss().leftBarChildDivider());
leftBarPanel.add(checklistDivider);
leftBarPanel.add(checklistPanel);
checklistPanel.addTask(new Task("Basic Information",
"Upload your picture, share a list of your skills and interests, provide a description of what you "
+ "do, and add your contact information."), personModelView.getAvatarId() != null
&& personModelView.getJobDescription() != null && personModelView.getInterests() != null
&& personModelView.getInterests().size() > 0);
final Task biographyTask = new Task("Biography", "Provide an overview of your professional background.",
"Work History & Education");
checklistPanel.addTask(biographyTask, false);
final Task workHistoryTask = new Task("Work History",
"List your past work experiences and related skills and achievements.", "Work History & Education");
checklistPanel.addTask(workHistoryTask, false);
final Task educationTask = new Task("Education",
"List the schools you have attended and degrees you have earned.", "Work History & Education");
checklistPanel.addTask(educationTask, false);
Session.getInstance().getEventBus().addObserver(GotPersonalBiographyResponseEvent.class,
new Observer<GotPersonalBiographyResponseEvent>()
{
public void update(final GotPersonalBiographyResponseEvent event)
{
if (event.getResponse() != null && !event.getResponse().equals(""))
{
checklistPanel.setTaskComplete(biographyTask);
}
}
});
Session.getInstance().getEventBus().addObserver(GotPersonalEducationResponseEvent.class,
new Observer<GotPersonalEducationResponseEvent>()
{
public void update(final GotPersonalEducationResponseEvent event)
{
if (event.getResponse().size() > 0)
{
checklistPanel.setTaskComplete(educationTask);
}
}
});
Session.getInstance().getEventBus().addObserver(GotPersonalEmploymentResponseEvent.class,
new Observer<GotPersonalEmploymentResponseEvent>()
{
public void update(final GotPersonalEmploymentResponseEvent event)
{
if (event.getResponse().size() > 0)
{
checklistPanel.setTaskComplete(workHistoryTask);
}
}
});
Session.getInstance().getActionProcessor().setQueueRequests(true);
PersonalBiographyModel.getInstance().fetch(personModelView.getAccountId(), true);
PersonalEducationModel.getInstance().fetch(personModelView.getId(), true);
PersonalEmploymentModel.getInstance().fetch(personModelView.getId(), true);
Session.getInstance().getActionProcessor().setQueueRequests(false);
Session.getInstance().getActionProcessor().fireQueuedRequests();
}
/**
* Creates and sets up the connections tab content.
*
* @param inPerson
* Person whose profile is being displayed.
* @return Tab content.
*/
private PagedListPanel createConnectionsTabContent(final PersonModelView inPerson)
{
final PagedListPanel connectionTabContent = new PagedListPanel("connections");
Session.getInstance().getEventBus().addObserver(GotPersonFollowersResponseEvent.class,
new Observer<GotPersonFollowersResponseEvent>()
{
public void update(final GotPersonFollowersResponseEvent event)
{
connectionTabContent.render(event.getResponse(), "No one is following this person");
}
});
Session.getInstance().getEventBus().addObserver(GotPersonFollowingResponseEvent.class,
new Observer<GotPersonFollowingResponseEvent>()
{
public void update(final GotPersonFollowingResponseEvent event)
{
connectionTabContent.render(event.getResponse(), "This person is not following anyone");
}
});
Session.getInstance().getEventBus().addObserver(GotPersonJoinedGroupsResponseEvent.class,
new Observer<GotPersonJoinedGroupsResponseEvent>()
{
public void update(final GotPersonJoinedGroupsResponseEvent event)
{
connectionTabContent.render(event.getResponse(), "This person is not following any groups");
}
});
connectionTabContent.addSet("Followers", PersonFollowersModel.getInstance(), new PersonRenderer(false),
new GetFollowersFollowingRequest(EntityType.PERSON, inPerson.getAccountId(), 0, 0));
connectionTabContent.addSet("Following", PersonFollowingModel.getInstance(), new PersonRenderer(false),
new GetFollowersFollowingRequest(EntityType.PERSON, inPerson.getAccountId(), 0, 0));
connectionTabContent.addSet("Groups", PersonJoinedGroupsModel.getInstance(), new GroupRenderer(),
new GetFollowersFollowingRequest(EntityType.GROUP, inPerson.getAccountId(), 0, 0));
return connectionTabContent;
}
}