| import { formatFeature, formatDirection } from "../utils/formatters"; |
|
|
| function getDirectionClassName(direction) { |
| const normalized = String(direction).toLowerCase(); |
| if (normalized === "increases" || normalized === "increase") return "driver-direction--increases"; |
| if (normalized === "decreases" || normalized === "decrease") return "driver-direction--decreases"; |
| return ""; |
| } |
|
|
| function formatSignedValue(value, decimals = 1) { |
| const prefix = value >= 0 ? "+" : ""; |
| return `${prefix}${value.toFixed(decimals)}`; |
| } |
|
|
| export function RiskDriversCard({ drivers }) { |
| const maxImpact = Math.max(...drivers.map((driver) => Math.abs(driver.impact_on_exceedance_probability)), 0.001); |
|
|
| return ( |
| <div className="card"> |
| <h2>Primary Risk Drivers</h2> |
| <p className="driver-explanation"> |
| These factors have the greatest influence on your product's risk profile. |
| Positive values indicate increased risk; negative values indicate decreased risk. |
| </p> |
| <div className="driver-list"> |
| {drivers.map((driver) => { |
| const width = `${(Math.abs(driver.impact_on_exceedance_probability) / maxImpact) * 100}%`; |
| const directionClassName = getDirectionClassName(driver.direction); |
| |
| const probImpact = driver.impact_on_exceedance_probability * 100; |
| const logImpact = driver.impact_on_final_log_cfu_g; |
| const shelfImpact = driver.impact_on_recommended_shelf_life_days; |
| |
| return ( |
| <div key={`${driver.feature}-${driver.variant_value}`} className="driver-item"> |
| <div className="driver-header"> |
| <strong>{formatFeature(driver.feature)}</strong> |
| <span className={`driver-direction ${directionClassName}`}> |
| {formatDirection(driver.direction)} |
| </span> |
| </div> |
| <div className="driver-bar-track"> |
| <div className="driver-bar-fill" style={{ width }} /> |
| </div> |
| <div className="driver-metrics"> |
| <span className={probImpact >= 0 ? "impact--negative" : "impact--positive"}> |
| Probability Impact: {formatSignedValue(probImpact)}% |
| </span> |
| <span className={logImpact >= 0 ? "impact--negative" : "impact--positive"}> |
| Growth Change: {formatSignedValue(logImpact, 2)} log CFU/g |
| </span> |
| <span className={shelfImpact <= 0 ? "impact--negative" : "impact--positive"}> |
| Shelf-Life Impact: {shelfImpact > 0 ? "+" : ""}{shelfImpact} days |
| </span> |
| </div> |
| </div> |
| ); |
| })} |
| </div> |
| </div> |
| ); |
| } |
|
|