Enhance CareerMapping component with node click functionality and detailed career display
Updated the CareerMapping component to allow users to click on nodes for detailed information about career fields and related careers. Introduced a new SelectedNodeInfo class to manage the display of selected node details. Improved data handling for career field and event nodes, ensuring accurate representation of related careers. Adjusted the network click event to trigger updates in the UI, enhancing interactivity and user experience.
This commit is contained in:
@@ -35,10 +35,28 @@ else
|
||||
<MudText Typo="Typo.body2" Class="mb-4 mud-text-secondary">
|
||||
This diagram shows the connections between events and their related career fields.
|
||||
Events are shown in blue, career fields in green. Career fields are clusters of related careers.
|
||||
Use mouse to zoom and pan the graph.
|
||||
Click on a node to see details. Use mouse to zoom and pan the graph.
|
||||
</MudText>
|
||||
|
||||
@if (_selectedNodeInfo != null)
|
||||
{
|
||||
<MudPaper Elevation="1" Class="pa-4 mb-4" Style="background-color: #f5f5f5;">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">@_selectedNodeInfo.Title</MudText>
|
||||
@if (_selectedNodeInfo.Careers != null && _selectedNodeInfo.Careers.Any())
|
||||
{
|
||||
<MudText Typo="Typo.subtitle2" Class="mb-2">Related Careers:</MudText>
|
||||
<MudStack Row="true" Spacing="1" WrapItems="true">
|
||||
@foreach (var career in _selectedNodeInfo.Careers.OrderBy(c => c))
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Variant="Variant.Filled" Color="Color.Default">@career</MudChip>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
<div style="width: 100%; height: 600px; border: 1px solid #ddd; border-radius: 4px;">
|
||||
<Network Id="careerMappingNetwork" Data="@_networkData" Options="@GetNetworkOptions"/>
|
||||
<Network Id="careerMappingNetwork" Data="@_networkData" Options="@GetNetworkOptions" OnClick="HandleNetworkClick"/>
|
||||
</div>
|
||||
</MudPaper>
|
||||
}
|
||||
@@ -46,6 +64,18 @@ else
|
||||
@code {
|
||||
private NetworkData? _networkData;
|
||||
private bool _isLoading = true;
|
||||
private Dictionary<int, List<string>> _fieldIdToCareers = new();
|
||||
private List<EventDefinition>? _allEvents;
|
||||
private Dictionary<string, int> _nodeIdToFieldId = new();
|
||||
private Dictionary<string, int> _nodeIdToEventId = new();
|
||||
private SelectedNodeInfo? _selectedNodeInfo;
|
||||
|
||||
private class SelectedNodeInfo
|
||||
{
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public bool IsCareerField { get; set; }
|
||||
public List<string>? Careers { get; set; }
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -69,8 +99,41 @@ else
|
||||
.Where(e => CareerFieldDefinitions.GetRelatedCareerFields(e.RelatedCareers).Any())
|
||||
.ToList();
|
||||
|
||||
_allEvents = eventsWithFields;
|
||||
|
||||
// Build mapping of career field IDs to their related careers
|
||||
_fieldIdToCareers.Clear();
|
||||
foreach (var evt in eventsWithFields)
|
||||
{
|
||||
var relatedFields = CareerFieldDefinitions.GetRelatedCareerFields(evt.RelatedCareers);
|
||||
foreach (var field in relatedFields)
|
||||
{
|
||||
if (!_fieldIdToCareers.ContainsKey(field.Id))
|
||||
{
|
||||
_fieldIdToCareers[field.Id] = new List<string>();
|
||||
}
|
||||
// Add unique career names for this field
|
||||
foreach (var career in evt.RelatedCareers)
|
||||
{
|
||||
var normalizedCareerName = CareerNormalizer.GetNormalizedKey(career.Name);
|
||||
// Check if this career matches the field
|
||||
var matchesField = field.DirectCareerMatches.Any(dcm =>
|
||||
string.Equals(CareerNormalizer.GetNormalizedKey(dcm), normalizedCareerName, StringComparison.OrdinalIgnoreCase)) ||
|
||||
field.PatternKeywords.Any(pk => normalizedCareerName.Contains(pk, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (matchesField && !_fieldIdToCareers[field.Id].Contains(career.Name, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
_fieldIdToCareers[field.Id].Add(career.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eventsWithFields.Any())
|
||||
{
|
||||
// Clear mappings before regenerating
|
||||
_nodeIdToFieldId.Clear();
|
||||
_nodeIdToEventId.Clear();
|
||||
_networkData = GenerateNetworkData(eventsWithFields);
|
||||
}
|
||||
}
|
||||
@@ -111,6 +174,9 @@ else
|
||||
Shape = "box",
|
||||
Size = 25
|
||||
});
|
||||
|
||||
// Store mapping for click handling
|
||||
_nodeIdToEventId[eventNodeId] = evt.Id;
|
||||
}
|
||||
|
||||
// Get related career fields for this event's careers
|
||||
@@ -141,6 +207,9 @@ else
|
||||
Shape = "box",
|
||||
Size = 20
|
||||
});
|
||||
|
||||
// Store mapping for click handling
|
||||
_nodeIdToFieldId[fieldNodeId] = field.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,4 +254,48 @@ else
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private void HandleNetworkClick(ClickEvent eventArg)
|
||||
{
|
||||
_selectedNodeInfo = null;
|
||||
|
||||
// Check if a node was clicked
|
||||
if (eventArg.Nodes != null && eventArg.Nodes.Count > 0)
|
||||
{
|
||||
var nodeId = eventArg.Nodes[0];
|
||||
|
||||
// Check if it's a career field node
|
||||
if (_nodeIdToFieldId.TryGetValue(nodeId, out var fieldId))
|
||||
{
|
||||
var field = CareerFieldDefinitions.GetAllCareerFields().FirstOrDefault(f => f.Id == fieldId);
|
||||
if (field != null)
|
||||
{
|
||||
_fieldIdToCareers.TryGetValue(fieldId, out var careers);
|
||||
_selectedNodeInfo = new SelectedNodeInfo
|
||||
{
|
||||
Title = field.Name,
|
||||
IsCareerField = true,
|
||||
Careers = careers?.ToList() ?? new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
// Check if it's an event node
|
||||
else if (_nodeIdToEventId.TryGetValue(nodeId, out var eventId) && _allEvents != null)
|
||||
{
|
||||
var evt = _allEvents.FirstOrDefault(e => e.Id == eventId);
|
||||
if (evt != null)
|
||||
{
|
||||
_selectedNodeInfo = new SelectedNodeInfo
|
||||
{
|
||||
Title = evt.Name,
|
||||
IsCareerField = false,
|
||||
Careers = evt.RelatedCareers.Select(c => c.Name).OrderBy(c => c).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user