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,174 @@
|
||||
/*
|
||||
You can use this wrapper to initialize peity charts globally. It will automatically detect the chart
|
||||
type based on the content of the element.
|
||||
|
||||
- You can also use the data-peity attribute to pass in options for the chart.
|
||||
- The data-peity attribute can be a JSON string or a string that can be parsed into a JSON object.
|
||||
- The wrapper will also handle the:
|
||||
-- updating of the chart with new data.
|
||||
-- negative values for the bar charts.
|
||||
-- color transitions for the bar charts.
|
||||
-- updating of the chart with new data.
|
||||
*/
|
||||
|
||||
import { PeityAPI } from './../thirdparty/peity.es6.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
'use strict';
|
||||
|
||||
// Global default settings for charts
|
||||
const defaults = {
|
||||
// Default background color for donut and pie charts (replaces the gray)
|
||||
donutBackground: 'var(--bs-border-color)', // Light purple background instead of gray
|
||||
pieBackground: 'var(--bs-border-color)' // Same for pie charts
|
||||
};
|
||||
|
||||
// Helper to create peity charts (similar to jQuery plugin style)
|
||||
function createPeity(selector, type, customOptions = {}) {
|
||||
document.querySelectorAll(selector).forEach(element => {
|
||||
// Parse data-peity attribute for options
|
||||
let options = {...customOptions};
|
||||
const dataAttr = element.getAttribute('data-peity');
|
||||
|
||||
if (dataAttr) {
|
||||
try {
|
||||
options = {...options, ...JSON.parse(dataAttr)};
|
||||
} catch (e) {
|
||||
console.warn('Invalid data-peity format for', selector);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply defaults for donut and pie charts background colors
|
||||
if (type === 'donut' || type === 'pie') {
|
||||
// If fill is not defined or is an empty array, set default colors
|
||||
if (!options.fill || options.fill.length === 0) {
|
||||
options.fill = type === 'donut' ?
|
||||
['var(--primary-500)', defaults.donutBackground] :
|
||||
['var(--primary-500)', defaults.pieBackground];
|
||||
}
|
||||
// If fill is defined but doesn't include a background color (for fractions like "1/4")
|
||||
else if (Array.isArray(options.fill) && options.fill.length === 1) {
|
||||
options.fill.push(type === 'donut' ? defaults.donutBackground : defaults.pieBackground);
|
||||
}
|
||||
// If data contains multiple values (e.g., "10,4,4,6"), don't add background
|
||||
}
|
||||
|
||||
PeityAPI.create(element, type, options);
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Simple chart initializations with default settings
|
||||
createPeity('.peity-pie', 'pie');
|
||||
createPeity('.peity-donut', 'donut');
|
||||
createPeity('.peity-line', 'line');
|
||||
createPeity('.peity-bar', 'bar');
|
||||
|
||||
// Updating chart with animation
|
||||
const updatingChart = document.querySelector('.updating-chart');
|
||||
if (updatingChart) {
|
||||
const values = updatingChart.textContent.split(',').map(Number);
|
||||
const chart = PeityAPI.create(updatingChart, 'line', {
|
||||
width: 200,
|
||||
height: 40,
|
||||
stroke: 'var(--info-500)',
|
||||
fill: 'var(--info-200)',
|
||||
min: 0,
|
||||
max: 10
|
||||
});
|
||||
|
||||
setInterval(function() {
|
||||
values.shift();
|
||||
values.push(Math.floor(Math.random() * 10));
|
||||
updatingChart.textContent = values.join(',');
|
||||
chart.draw();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Bar charts with negative values (red/green coloring)
|
||||
document.querySelectorAll('.bar-negative').forEach(element => {
|
||||
const values = element.textContent.split(',').map(Number);
|
||||
PeityAPI.create(element, 'bar', {
|
||||
height: 40,
|
||||
width: 110,
|
||||
fill: values.map(value => value > 0 ? 'var(--success-500)' : 'var(--danger-500)')
|
||||
});
|
||||
});
|
||||
|
||||
// Bar charts with color transitions
|
||||
document.querySelectorAll('.bar-transition').forEach(element => {
|
||||
const values = element.textContent.split(',').map(Number);
|
||||
PeityAPI.create(element, 'bar', {
|
||||
height: 40,
|
||||
width: 110,
|
||||
fill: values.map((_, i, all) => {
|
||||
const g = parseInt((i / all.length) * 255);
|
||||
return `rgb(255, ${g}, ${g})`;
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
// Process all remaining elements with data-peity attribute
|
||||
document.querySelectorAll('[data-peity]').forEach(element => {
|
||||
// Skip elements already handled by specific selectors
|
||||
if (element.classList.contains('peity-pie') ||
|
||||
element.classList.contains('peity-donut') ||
|
||||
element.classList.contains('peity-line') ||
|
||||
element.classList.contains('peity-bar') ||
|
||||
element.classList.contains('updating-chart') ||
|
||||
element.classList.contains('bar-negative') ||
|
||||
element.classList.contains('bar-transition')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto-detect chart type based on content
|
||||
const content = element.textContent.trim();
|
||||
let type;
|
||||
|
||||
if (content.includes('/')) {
|
||||
type = 'donut'; // Fraction data is best for donut
|
||||
} else if (content.includes(',')) {
|
||||
// If it has commas, it's likely a series
|
||||
const hasNegative = content.split(',').some(val => parseFloat(val) < 0);
|
||||
type = hasNegative ? 'bar' : 'line'; // Bars handle negative values better visually
|
||||
} else {
|
||||
type = 'pie'; // Default fallback
|
||||
}
|
||||
|
||||
// Get options from data attribute
|
||||
let options = {};
|
||||
const dataAttr = element.getAttribute('data-peity');
|
||||
if (dataAttr) {
|
||||
try {
|
||||
options = JSON.parse(dataAttr);
|
||||
} catch (e) {
|
||||
console.warn('Invalid data-peity format for element', element);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply global background color for donut/pie charts
|
||||
if ((type === 'donut' || type === 'pie') && content.includes('/')) {
|
||||
// For fraction notation (e.g. "1/4"), make sure we have a background color
|
||||
if (!options.fill || !Array.isArray(options.fill) || options.fill.length < 2) {
|
||||
options.fill = options.fill || [];
|
||||
// If we have one color already, keep it and add the background
|
||||
if (options.fill.length === 1) {
|
||||
options.fill.push(type === 'donut' ? defaults.donutBackground : defaults.pieBackground);
|
||||
} else {
|
||||
// No colors defined yet, set defaults
|
||||
options.fill = [
|
||||
type === 'donut' ? 'var(--primary-500)' : 'var(--success-500)',
|
||||
type === 'donut' ? defaults.donutBackground : defaults.pieBackground
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create chart
|
||||
PeityAPI.create(element, type, options);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error initializing Peity charts:', error);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user