fix: implement Blazor-native login form to properly update authentication state
TaxBaik CI/CD / build-and-deploy (push) Successful in 2m26s
TaxBaik CI/CD / build-and-deploy (push) Successful in 2m26s
Problem: JavaScript login form saved tokens to localStorage but didn't notify CustomAuthenticationStateProvider, causing [Authorize] pages to remain in 'loading' state indefinitely. The provider only reads tokens when: 1. GetAuthenticationStateAsync() is called (page load) 2. NotifyAuthenticationStateChanged() is triggered (UI updates) But JavaScript login didn't trigger either, leaving the authentication state stale. Solution: Convert AdminLoginForm from HTML+JavaScript to pure Blazor component. Now the login flow is: 1. User enters credentials in Blazor form 2. HttpClient POST to /api/auth/login 3. Save tokens to localStorage 4. Call CustomAuthenticationStateProvider.LoginAsync() directly 5. Blazor detects auth state change and re-evaluates [Authorize] pages 6. Dashboard [Authorize] page renders successfully Result: Immediate authentication state update, no loading timeout on protected pages. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
(function() {
|
||||
// Function to create the tree view
|
||||
function createTreeView(data, container, level) {
|
||||
var treeItem = document.createElement('div');
|
||||
treeItem.className = 'tree-item ' + (data.type === 'directory' ? 'directory-item' : 'file-item');
|
||||
|
||||
// Auto-expand directories up to level 4
|
||||
var isExpanded = data.type === 'directory' && level <= 2;
|
||||
if (isExpanded) {
|
||||
treeItem.className += ' expanded';
|
||||
} else if (data.type === 'directory') {
|
||||
treeItem.className += ' collapsed';
|
||||
}
|
||||
|
||||
var itemContent = document.createElement('div');
|
||||
itemContent.className = 'tree-item-content';
|
||||
|
||||
var toggleIcon = document.createElement('span');
|
||||
toggleIcon.className = 'toggle-icon';
|
||||
itemContent.appendChild(toggleIcon);
|
||||
|
||||
var icon = document.createElement('span');
|
||||
icon.className = 'tree-item-icon ' + (data.type === 'directory' ? 'directory-icon' : 'file-icon');
|
||||
icon.innerHTML = data.type === 'directory' ? '📁' : '📄';
|
||||
itemContent.appendChild(icon);
|
||||
|
||||
var name = document.createElement('span');
|
||||
name.className = 'tree-item-name';
|
||||
name.textContent = data.name;
|
||||
itemContent.appendChild(name);
|
||||
|
||||
if (data.path) {
|
||||
var path = document.createElement('span');
|
||||
path.className = 'path';
|
||||
path.textContent = data.path;
|
||||
itemContent.appendChild(path);
|
||||
}
|
||||
|
||||
treeItem.appendChild(itemContent);
|
||||
|
||||
if (data.type === 'directory' && data.children && data.children.length > 0) {
|
||||
var childrenContainer = document.createElement('div');
|
||||
childrenContainer.className = 'tree-item-children';
|
||||
|
||||
// Sort children: directories first, then files, both alphabetically
|
||||
var sortedChildren = data.children.slice();
|
||||
sortedChildren.sort(function(a, b) {
|
||||
if (a.type === b.type) {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
return a.type === 'directory' ? -1 : 1;
|
||||
});
|
||||
|
||||
for (var i = 0; i < sortedChildren.length; i++) {
|
||||
createTreeView(sortedChildren[i], childrenContainer, level + 1);
|
||||
}
|
||||
|
||||
treeItem.appendChild(childrenContainer);
|
||||
|
||||
// Add click event to toggle directory
|
||||
itemContent.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
if (treeItem.classList.contains('expanded')) {
|
||||
treeItem.classList.remove('expanded');
|
||||
treeItem.classList.add('collapsed');
|
||||
} else {
|
||||
treeItem.classList.remove('collapsed');
|
||||
treeItem.classList.add('expanded');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
container.appendChild(treeItem);
|
||||
}
|
||||
|
||||
// Function to load directory data using AJAX
|
||||
function loadDirectoryData() {
|
||||
var treeViewContainer = document.getElementById('tree-view');
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
var directoryData = JSON.parse(xhr.responseText);
|
||||
treeViewContainer.innerHTML = '';
|
||||
createTreeView(directoryData, treeViewContainer, 1);
|
||||
} catch (e) {
|
||||
treeViewContainer.innerHTML = '<div class="error">Error parsing JSON data: ' + e.message + '</div>';
|
||||
}
|
||||
} else {
|
||||
treeViewContainer.innerHTML = '<div class="error">Failed to load directory data. Status: ' + xhr.status + '</div>';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open('GET', 'json/directory-tree.json', true);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// Load the directory data when the page loads
|
||||
window.addEventListener('load', loadDirectoryData);
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user