-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hackathon - Heart Essential 8 #289
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThe recent updates introduce the Changes
Recent review detailsConfiguration used: CodeRabbit UI Files ignored due to path filters (8)
Files selected for processing (3)
Files skipped from review as they are similar to previous changes (2)
Additional context usedBiome
Additional comments not posted (7)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Outside diff range, codebase verification and nitpick comments (2)
src/components/container/HeartEssentialEight/HeartEssentialEight.stories.tsx (1)
1-62
: LGTM! Consider improving readability.The Storybook stories for
HeartEssentialEight
are well-structured and comprehensive. Consider using a loop or a helper function to populatecustomFieldDictionary
if the list grows, to enhance maintainability.src/components/container/HeartEssentialEight/HeartEssentialEight.css (1)
43-45
: Remove outdated vendor prefixes.The
-moz-border-radius
and-webkit-border-radius
prefixes are no longer necessary for modern browsers.- -moz-border-radius: 50px; - -webkit-border-radius: 50px; border-radius: 50px;Also applies to: 63-65
src/components/container/HeartEssentialEight/HeartEssentialEight.css
Outdated
Show resolved
Hide resolved
) { | ||
const map = newAchievementMap as Record<string, boolean>; | ||
const achievementList: any[] = []; | ||
for (const key in map) { | ||
const vv = map[key]; | ||
if (vv === didAchieve) { | ||
const title = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => { | ||
return str.toUpperCase(); | ||
}); | ||
let icon: any; | ||
let url: string; | ||
const circleClasses: string[] = ["circle"]; | ||
switch (key) { | ||
case "Activity": | ||
icon = iconGetActive; | ||
circleClasses.push("activity"); | ||
break; | ||
case "BloodPressure": | ||
icon = iconManageBloodPressure; | ||
circleClasses.push("bloodPressure"); | ||
break; | ||
case "BloodSugar": | ||
icon = iconReduceBloodSugar; | ||
circleClasses.push("bloodSugar"); | ||
break; | ||
case "BMI": | ||
icon = iconLoseWeight; | ||
circleClasses.push("bmi"); | ||
break; | ||
case "Cholesterol": | ||
icon = iconCholesterol; | ||
circleClasses.push("cholesterol"); | ||
break; | ||
case "Diet": | ||
icon = iconEatWell; | ||
circleClasses.push("diet"); | ||
break; | ||
case "Nicotine": | ||
icon = iconStopSmoking; | ||
circleClasses.push("nicotine"); | ||
break; | ||
case "Sleep": | ||
icon = iconSleep; | ||
circleClasses.push("sleep"); | ||
break; | ||
default: | ||
icon = null; | ||
} | ||
|
||
const achievementIcon = ( | ||
<div className={circleClasses.join(" ")}> | ||
<img src={icon} /> | ||
</div> | ||
); | ||
|
||
const achievement = ( | ||
<Action key={`achievement-${key}`} | ||
title={title} | ||
titleIcon={achievementIcon} | ||
onClick={() => MyDataHelps.openExternalUrl(url)} | ||
/> | ||
); | ||
achievementList.push(achievement); | ||
} | ||
} | ||
|
||
return achievementList; | ||
} | ||
|
||
useInitializeView(initialize, [], [props.previewState]); | ||
|
||
return ( | ||
<> | ||
{/* <LoadingIndicator /> */} | ||
{/* {score === undefined && <LoadingIndicator />} */} | ||
<div className="mdhui-heart-e8-container"> | ||
<div className="mdhui-heart-e8-score-container"> | ||
<ProgressRing | ||
percentCompleted={score} | ||
color="rgb(193, 14, 33)" | ||
children={ | ||
<div className="scoreContainer"> | ||
<div className="score">{score}</div> | ||
<div className="scoreSubText">out of 100</div> | ||
</div> | ||
} | ||
animate={true} | ||
/> | ||
</div> | ||
{achievementMap && <div className="mdhui-heart-e8-feedback"> | ||
<div className="achievementSection"><div className="bulletPoint improve" /><h3>IMPROVE</h3></div> | ||
<div className="achievementSection">{generateAchievementMap(false, achievementMap)}</div> | ||
<div className="achievementSection"><div className="bulletPoint celebrate" /><h3>CELEBRATE</h3></div> | ||
<div className="achievementSection">{generateAchievementMap(true, achievementMap)}</div> | ||
</div>} | ||
</div> | ||
|
||
</> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid using the children
prop directly in JSX.
The ProgressRing
component should use JSX syntax to pass children, as recommended by React best practices.
- <ProgressRing
- percentCompleted={score}
- color="rgb(193, 14, 33)"
- children={
- <div className="scoreContainer">
- <div className="score">{score}</div>
- <div className="scoreSubText">out of 100</div>
- </div>
- }
- animate={true}
- />
+ <ProgressRing percentCompleted={score} color="rgb(193, 14, 33)" animate={true}>
+ <div className="scoreContainer">
+ <div className="score">{score}</div>
+ <div className="scoreSubText">out of 100</div>
+ </div>
+ </ProgressRing>
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export default function (props: HeartEssentialEightProps) { | |
const { customFieldDictionary } = props; | |
let [score, setScore] = React.useState<number>(); | |
let [achievementMap, setAchievementMap] = | |
useState<Record<HeartEssentialEightScores, boolean>>(); | |
async function initialize() { | |
if (props.previewState) { | |
if (["Default", "NoData"].includes(props.previewState ?? "")) { | |
const data = | |
props.previewState === "Default" ? previewHeartEssentialData : {}; | |
loadScoresFromCustomFieldData(data); | |
} else { | |
MyDataHelps.getParticipantInfo().then((participantInfo) => { | |
loadScoresFromCustomFieldData(participantInfo.customFields); | |
}); | |
} | |
} | |
} | |
function loadScoresFromCustomFieldData( | |
customFieldData: Record<string, string> | |
) { | |
let newScore: number = 0; | |
let newAchievementMap = {} as Record<HeartEssentialEightScores, boolean>; | |
for (const key in customFieldDictionary) { | |
if (customFieldDictionary[key]) { | |
let surveyScore = customFieldData[customFieldDictionary[key]]; | |
let numericScore = parseInt(surveyScore); | |
if (!Number.isNaN(numericScore)) { | |
newScore += numericScore; | |
newAchievementMap[key as HeartEssentialEightScores] = | |
numericScore >= 100; | |
} else { | |
newAchievementMap[key as HeartEssentialEightScores] = false; | |
} | |
} | |
} | |
if (newScore > 0){ | |
newScore = (newScore / 800) * 100; | |
} | |
setScore(parseFloat(newScore.toFixed(1))); | |
setAchievementMap(newAchievementMap); | |
} | |
function generateAchievementMap( | |
didAchieve: boolean, | |
newAchievementMap: Record<HeartEssentialEightScores, boolean> | |
) { | |
const map = newAchievementMap as Record<string, boolean>; | |
const achievementList: any[] = []; | |
for (const key in map) { | |
const vv = map[key]; | |
if (vv === didAchieve) { | |
const title = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => { | |
return str.toUpperCase(); | |
}); | |
let icon: any; | |
let url: string; | |
const circleClasses: string[] = ["circle"]; | |
switch (key) { | |
case "Activity": | |
icon = iconGetActive; | |
circleClasses.push("activity"); | |
break; | |
case "BloodPressure": | |
icon = iconManageBloodPressure; | |
circleClasses.push("bloodPressure"); | |
break; | |
case "BloodSugar": | |
icon = iconReduceBloodSugar; | |
circleClasses.push("bloodSugar"); | |
break; | |
case "BMI": | |
icon = iconLoseWeight; | |
circleClasses.push("bmi"); | |
break; | |
case "Cholesterol": | |
icon = iconCholesterol; | |
circleClasses.push("cholesterol"); | |
break; | |
case "Diet": | |
icon = iconEatWell; | |
circleClasses.push("diet"); | |
break; | |
case "Nicotine": | |
icon = iconStopSmoking; | |
circleClasses.push("nicotine"); | |
break; | |
case "Sleep": | |
icon = iconSleep; | |
circleClasses.push("sleep"); | |
break; | |
default: | |
icon = null; | |
} | |
const achievementIcon = ( | |
<div className={circleClasses.join(" ")}> | |
<img src={icon} /> | |
</div> | |
); | |
const achievement = ( | |
<Action key={`achievement-${key}`} | |
title={title} | |
titleIcon={achievementIcon} | |
onClick={() => MyDataHelps.openExternalUrl(url)} | |
/> | |
); | |
achievementList.push(achievement); | |
} | |
} | |
return achievementList; | |
} | |
useInitializeView(initialize, [], [props.previewState]); | |
return ( | |
<> | |
{/* <LoadingIndicator /> */} | |
{/* {score === undefined && <LoadingIndicator />} */} | |
<div className="mdhui-heart-e8-container"> | |
<div className="mdhui-heart-e8-score-container"> | |
<ProgressRing | |
percentCompleted={score} | |
color="rgb(193, 14, 33)" | |
children={ | |
<div className="scoreContainer"> | |
<div className="score">{score}</div> | |
<div className="scoreSubText">out of 100</div> | |
</div> | |
} | |
animate={true} | |
/> | |
</div> | |
{achievementMap && <div className="mdhui-heart-e8-feedback"> | |
<div className="achievementSection"><div className="bulletPoint improve" /><h3>IMPROVE</h3></div> | |
<div className="achievementSection">{generateAchievementMap(false, achievementMap)}</div> | |
<div className="achievementSection"><div className="bulletPoint celebrate" /><h3>CELEBRATE</h3></div> | |
<div className="achievementSection">{generateAchievementMap(true, achievementMap)}</div> | |
</div>} | |
</div> | |
</> | |
); | |
} | |
return ( | |
<> | |
{/* <LoadingIndicator /> */} | |
{/* {score === undefined && <LoadingIndicator />} */} | |
<div className="mdhui-heart-e8-container"> | |
<div className="mdhui-heart-e8-score-container"> | |
<ProgressRing percentCompleted={score} color="rgb(193, 14, 33)" animate={true}> | |
<div className="scoreContainer"> | |
<div className="score">{score}</div> | |
<div className="scoreSubText">out of 100</div> | |
</div> | |
</ProgressRing> | |
</div> | |
{achievementMap && <div className="mdhui-heart-e8-feedback"> | |
<div className="achievementSection"><div className="bulletPoint improve" /><h3>IMPROVE</h3></div> | |
<div className="achievementSection">{generateAchievementMap(false, achievementMap)}</div> | |
<div className="achievementSection"><div className="bulletPoint celebrate" /><h3>CELEBRATE</h3></div> | |
<div className="achievementSection">{generateAchievementMap(true, achievementMap)}</div> | |
</div>} | |
</div> | |
</> | |
); |
Tools
Biome
[error] 165-165: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
async function initialize() { | ||
if (props.previewState) { | ||
if (["Default", "NoData"].includes(props.previewState ?? "")) { | ||
const data = | ||
props.previewState === "Default" ? previewHeartEssentialData : {}; | ||
loadScoresFromCustomFieldData(data); | ||
} | ||
} else { | ||
MyDataHelps.getParticipantInfo().then((participantInfo) => { | ||
loadScoresFromCustomFieldData(participantInfo.customFields); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling to async operations.
Consider adding error handling to the MyDataHelps.getParticipantInfo()
promise to manage potential errors gracefully.
MyDataHelps.getParticipantInfo()
.then((participantInfo) => {
loadScoresFromCustomFieldData(participantInfo.customFields);
})
.catch((error) => {
console.error("Failed to fetch participant info:", error);
});
export default function (props: HeartEssentialEightProps) { | ||
const { customFieldDictionary } = props; | ||
let [score, setScore] = React.useState<number>(); | ||
let [achievementMap, setAchievementMap] = | ||
useState<Record<HeartEssentialEightScores, boolean>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use const
for state variables.
The use of let
for score
and achievementMap
is unconventional. Consider using const
as these variables are managed by React state hooks.
- let [score, setScore] = React.useState<number>();
- let [achievementMap, setAchievementMap] = useState<Record<HeartEssentialEightScores, boolean>>();
+ const [score, setScore] = React.useState<number>();
+ const [achievementMap, setAchievementMap] = useState<Record<HeartEssentialEightScores, boolean>>();
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export default function (props: HeartEssentialEightProps) { | |
const { customFieldDictionary } = props; | |
let [score, setScore] = React.useState<number>(); | |
let [achievementMap, setAchievementMap] = | |
useState<Record<HeartEssentialEightScores, boolean>>(); | |
export default function (props: HeartEssentialEightProps) { | |
const { customFieldDictionary } = props; | |
const [score, setScore] = React.useState<number>(); | |
const [achievementMap, setAchievementMap] = | |
useState<Record<HeartEssentialEightScores, boolean>>(); |
return ( | ||
<> | ||
{/* <LoadingIndicator /> */} | ||
{/* {score === undefined && <LoadingIndicator />} */} | ||
<div className="mdhui-heart-e8-container"> | ||
<div className="mdhui-heart-e8-score-container"> | ||
<ProgressRing | ||
percentCompleted={score} | ||
color="rgb(193, 14, 33)" | ||
children={ | ||
<div className="scoreContainer"> | ||
<div className="score">{score}</div> | ||
<div className="scoreSubText">out of 100</div> | ||
</div> | ||
} | ||
animate={true} | ||
/> | ||
</div> | ||
{achievementMap && <div className="mdhui-heart-e8-feedback"> | ||
<div className="achievementSection"><div className="bulletPoint improve" /><h3>IMPROVE</h3></div> | ||
<div className="achievementSection">{generateAchievementMap(false, achievementMap)}</div> | ||
<div className="achievementSection"><div className="bulletPoint celebrate" /><h3>CELEBRATE</h3></div> | ||
<div className="achievementSection">{generateAchievementMap(true, achievementMap)}</div> | ||
</div>} | ||
</div> | ||
|
||
</> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid using the children
prop directly in JSX.
The ProgressRing
component should use JSX syntax to pass children, as recommended by React best practices.
- <ProgressRing
- percentCompleted={score}
- color="rgb(193, 14, 33)"
- children={
- <div className="scoreContainer">
- <div className="score">{score}</div>
- <div className="scoreSubText">out of 100</div>
- </div>
- }
- animate={true}
- />
+ <ProgressRing percentCompleted={score} color="rgb(193, 14, 33)" animate={true}>
+ <div className="scoreContainer">
+ <div className="score">{score}</div>
+ <div className="scoreSubText">out of 100</div>
+ </div>
+ </ProgressRing>
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
return ( | |
<> | |
{/* <LoadingIndicator /> */} | |
{/* {score === undefined && <LoadingIndicator />} */} | |
<div className="mdhui-heart-e8-container"> | |
<div className="mdhui-heart-e8-score-container"> | |
<ProgressRing | |
percentCompleted={score} | |
color="rgb(193, 14, 33)" | |
children={ | |
<div className="scoreContainer"> | |
<div className="score">{score}</div> | |
<div className="scoreSubText">out of 100</div> | |
</div> | |
} | |
animate={true} | |
/> | |
</div> | |
{achievementMap && <div className="mdhui-heart-e8-feedback"> | |
<div className="achievementSection"><div className="bulletPoint improve" /><h3>IMPROVE</h3></div> | |
<div className="achievementSection">{generateAchievementMap(false, achievementMap)}</div> | |
<div className="achievementSection"><div className="bulletPoint celebrate" /><h3>CELEBRATE</h3></div> | |
<div className="achievementSection">{generateAchievementMap(true, achievementMap)}</div> | |
</div>} | |
</div> | |
</> | |
); | |
return ( | |
<> | |
{/* <LoadingIndicator /> */} | |
{/* {score === undefined && <LoadingIndicator />} */} | |
<div className="mdhui-heart-e8-container"> | |
<div className="mdhui-heart-e8-score-container"> | |
<ProgressRing percentCompleted={score} color="rgb(193, 14, 33)" animate={true}> | |
<div className="scoreContainer"> | |
<div className="score">{score}</div> | |
<div className="scoreSubText">out of 100</div> | |
</div> | |
</ProgressRing> | |
</div> | |
{achievementMap && <div className="mdhui-heart-e8-feedback"> | |
<div className="achievementSection"><div className="bulletPoint improve" /><h3>IMPROVE</h3></div> | |
<div className="achievementSection">{generateAchievementMap(false, achievementMap)}</div> | |
<div className="achievementSection"><div className="bulletPoint celebrate" /><h3>CELEBRATE</h3></div> | |
<div className="achievementSection">{generateAchievementMap(true, achievementMap)}</div> | |
</div>} | |
</div> | |
</> | |
); |
Tools
Biome
[error] 166-166: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
function loadScoresFromCustomFieldData( | ||
customFieldData: Record<string, string> | ||
) { | ||
let newScore: number = 0; | ||
let newAchievementMap = {} as Record<HeartEssentialEightScores, boolean>; | ||
|
||
for (const key in customFieldDictionary) { | ||
if (customFieldDictionary[key]) { | ||
let surveyScore = customFieldData[customFieldDictionary[key]]; | ||
let numericScore = parseInt(surveyScore); | ||
if (!Number.isNaN(numericScore)) { | ||
newScore += numericScore; | ||
newAchievementMap[key as HeartEssentialEightScores] = | ||
numericScore >= 100; | ||
} else { | ||
newAchievementMap[key as HeartEssentialEightScores] = false; | ||
} | ||
} | ||
} | ||
|
||
if (newScore > 0){ | ||
newScore = (newScore / 800) * 100; | ||
} | ||
|
||
setScore(parseFloat(newScore.toFixed(1))); | ||
setAchievementMap(newAchievementMap); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve type safety for newAchievementMap
.
Consider initializing newAchievementMap
with a more explicit type to enhance type safety.
- let newAchievementMap = {} as Record<HeartEssentialEightScores, boolean>;
+ let newAchievementMap: Record<HeartEssentialEightScores, boolean> = {};
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
function loadScoresFromCustomFieldData( | |
customFieldData: Record<string, string> | |
) { | |
let newScore: number = 0; | |
let newAchievementMap = {} as Record<HeartEssentialEightScores, boolean>; | |
for (const key in customFieldDictionary) { | |
if (customFieldDictionary[key]) { | |
let surveyScore = customFieldData[customFieldDictionary[key]]; | |
let numericScore = parseInt(surveyScore); | |
if (!Number.isNaN(numericScore)) { | |
newScore += numericScore; | |
newAchievementMap[key as HeartEssentialEightScores] = | |
numericScore >= 100; | |
} else { | |
newAchievementMap[key as HeartEssentialEightScores] = false; | |
} | |
} | |
} | |
if (newScore > 0){ | |
newScore = (newScore / 800) * 100; | |
} | |
setScore(parseFloat(newScore.toFixed(1))); | |
setAchievementMap(newAchievementMap); | |
} | |
function loadScoresFromCustomFieldData( | |
customFieldData: Record<string, string> | |
) { | |
let newScore: number = 0; | |
let newAchievementMap: Record<HeartEssentialEightScores, boolean> = {}; | |
for (const key in customFieldDictionary) { | |
if (customFieldDictionary[key]) { | |
let surveyScore = customFieldData[customFieldDictionary[key]]; | |
let numericScore = parseInt(surveyScore); | |
if (!Number.isNaN(numericScore)) { | |
newScore += numericScore; | |
newAchievementMap[key as HeartEssentialEightScores] = | |
numericScore >= 100; | |
} else { | |
newAchievementMap[key as HeartEssentialEightScores] = false; | |
} | |
} | |
} | |
if (newScore > 0){ | |
newScore = (newScore / 800) * 100; | |
} | |
setScore(parseFloat(newScore.toFixed(1))); | |
setAchievementMap(newAchievementMap); | |
} |
function generateAchievementMap( | ||
didAchieve: boolean, | ||
newAchievementMap: Record<HeartEssentialEightScores, boolean> | ||
) { | ||
const map = newAchievementMap as Record<string, boolean>; | ||
const achievementList: any[] = []; | ||
for (const key in map) { | ||
const vv = map[key]; | ||
if (vv === didAchieve) { | ||
const title = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => { | ||
return str.toUpperCase(); | ||
}); | ||
let icon: any; | ||
let url: string; | ||
const circleClasses: string[] = ["circle"]; | ||
switch (key) { | ||
case "Activity": | ||
icon = iconGetActive; | ||
circleClasses.push("activity"); | ||
break; | ||
case "BloodPressure": | ||
icon = iconManageBloodPressure; | ||
circleClasses.push("bloodPressure"); | ||
break; | ||
case "BloodSugar": | ||
icon = iconReduceBloodSugar; | ||
circleClasses.push("bloodSugar"); | ||
break; | ||
case "BMI": | ||
icon = iconLoseWeight; | ||
circleClasses.push("bmi"); | ||
break; | ||
case "Cholesterol": | ||
icon = iconCholesterol; | ||
circleClasses.push("cholesterol"); | ||
break; | ||
case "Diet": | ||
icon = iconEatWell; | ||
circleClasses.push("diet"); | ||
break; | ||
case "Nicotine": | ||
icon = iconStopSmoking; | ||
circleClasses.push("nicotine"); | ||
break; | ||
case "Sleep": | ||
icon = iconSleep; | ||
circleClasses.push("sleep"); | ||
break; | ||
default: | ||
icon = null; | ||
} | ||
|
||
const achievementIcon = ( | ||
<div className={circleClasses.join(" ")}> | ||
<img src={icon} /> | ||
</div> | ||
); | ||
|
||
const achievement = ( | ||
<Action key={`achievement-${key}`} | ||
title={title} | ||
titleIcon={achievementIcon} | ||
onClick={() => MyDataHelps.openExternalUrl(url)} | ||
/> | ||
); | ||
achievementList.push(achievement); | ||
} | ||
} | ||
|
||
return achievementList; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enhance type safety and readability.
Consider using more specific types for map
and achievementList
to enhance type safety and readability.
- const map = newAchievementMap as Record<string, boolean>;
- const achievementList: any[] = [];
+ const map: Record<HeartEssentialEightScores, boolean> = newAchievementMap;
+ const achievementList: JSX.Element[] = [];
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
function generateAchievementMap( | |
didAchieve: boolean, | |
newAchievementMap: Record<HeartEssentialEightScores, boolean> | |
) { | |
const map = newAchievementMap as Record<string, boolean>; | |
const achievementList: any[] = []; | |
for (const key in map) { | |
const vv = map[key]; | |
if (vv === didAchieve) { | |
const title = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => { | |
return str.toUpperCase(); | |
}); | |
let icon: any; | |
let url: string; | |
const circleClasses: string[] = ["circle"]; | |
switch (key) { | |
case "Activity": | |
icon = iconGetActive; | |
circleClasses.push("activity"); | |
break; | |
case "BloodPressure": | |
icon = iconManageBloodPressure; | |
circleClasses.push("bloodPressure"); | |
break; | |
case "BloodSugar": | |
icon = iconReduceBloodSugar; | |
circleClasses.push("bloodSugar"); | |
break; | |
case "BMI": | |
icon = iconLoseWeight; | |
circleClasses.push("bmi"); | |
break; | |
case "Cholesterol": | |
icon = iconCholesterol; | |
circleClasses.push("cholesterol"); | |
break; | |
case "Diet": | |
icon = iconEatWell; | |
circleClasses.push("diet"); | |
break; | |
case "Nicotine": | |
icon = iconStopSmoking; | |
circleClasses.push("nicotine"); | |
break; | |
case "Sleep": | |
icon = iconSleep; | |
circleClasses.push("sleep"); | |
break; | |
default: | |
icon = null; | |
} | |
const achievementIcon = ( | |
<div className={circleClasses.join(" ")}> | |
<img src={icon} /> | |
</div> | |
); | |
const achievement = ( | |
<Action key={`achievement-${key}`} | |
title={title} | |
titleIcon={achievementIcon} | |
onClick={() => MyDataHelps.openExternalUrl(url)} | |
/> | |
); | |
achievementList.push(achievement); | |
} | |
} | |
return achievementList; | |
} | |
function generateAchievementMap( | |
didAchieve: boolean, | |
newAchievementMap: Record<HeartEssentialEightScores, boolean> | |
) { | |
const map: Record<HeartEssentialEightScores, boolean> = newAchievementMap; | |
const achievementList: JSX.Element[] = []; | |
for (const key in map) { | |
const vv = map[key]; | |
if (vv === didAchieve) { | |
const title = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => { | |
return str.toUpperCase(); | |
}); | |
let icon: any; | |
let url: string; | |
const circleClasses: string[] = ["circle"]; | |
switch (key) { | |
case "Activity": | |
icon = iconGetActive; | |
circleClasses.push("activity"); | |
break; | |
case "BloodPressure": | |
icon = iconManageBloodPressure; | |
circleClasses.push("bloodPressure"); | |
break; | |
case "BloodSugar": | |
icon = iconReduceBloodSugar; | |
circleClasses.push("bloodSugar"); | |
break; | |
case "BMI": | |
icon = iconLoseWeight; | |
circleClasses.push("bmi"); | |
break; | |
case "Cholesterol": | |
icon = iconCholesterol; | |
circleClasses.push("cholesterol"); | |
break; | |
case "Diet": | |
icon = iconEatWell; | |
circleClasses.push("diet"); | |
break; | |
case "Nicotine": | |
icon = iconStopSmoking; | |
circleClasses.push("nicotine"); | |
break; | |
case "Sleep": | |
icon = iconSleep; | |
circleClasses.push("sleep"); | |
break; | |
default: | |
icon = null; | |
} | |
const achievementIcon = ( | |
<div className={circleClasses.join(" ")}> | |
<img src={icon} /> | |
</div> | |
); | |
const achievement = ( | |
<Action key={`achievement-${key}`} | |
title={title} | |
titleIcon={achievementIcon} | |
onClick={() => MyDataHelps.openExternalUrl(url)} | |
/> | |
); | |
achievementList.push(achievement); | |
} | |
} | |
return achievementList; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
async function initialize() { | ||
if (props.previewState) { | ||
if (["Default", "NoData"].includes(props.previewState ?? "")) { | ||
const data = | ||
props.previewState === "Default" ? previewHeartEssentialData : {}; | ||
loadScoresFromCustomFieldData(data); | ||
} | ||
} else { | ||
MyDataHelps.getParticipantInfo().then((participantInfo) => { | ||
loadScoresFromCustomFieldData(participantInfo.customFields); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling to async operations.
Consider adding error handling to the MyDataHelps.getParticipantInfo()
promise to manage potential errors gracefully.
MyDataHelps.getParticipantInfo()
.then((participantInfo) => {
loadScoresFromCustomFieldData(participantInfo.customFields);
})
.catch((error) => {
console.error("Failed to fetch participant info:", error);
});
function loadScoresFromCustomFieldData( | ||
customFieldData: Record<string, string> | ||
) { | ||
let newScore: number = 0; | ||
let newAchievementMap = {} as Record<HeartEssentialEightScores, boolean>; | ||
|
||
for (const key in props.customFieldDictionary) { | ||
if (props.customFieldDictionary[key]) { | ||
let surveyScore = customFieldData[props.customFieldDictionary[key]]; | ||
let numericScore = parseInt(surveyScore); | ||
if (!Number.isNaN(numericScore)) { | ||
newScore += numericScore; | ||
newAchievementMap[key as HeartEssentialEightScores] = | ||
numericScore >= 100; | ||
} else { | ||
newAchievementMap[key as HeartEssentialEightScores] = false; | ||
} | ||
} | ||
} | ||
|
||
if (newScore > 0) { | ||
newScore = (newScore / 800) * 100; | ||
} | ||
|
||
setScore(parseFloat(newScore.toFixed(1))); | ||
setAchievementMap(newAchievementMap); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve type safety for newAchievementMap
.
Consider initializing newAchievementMap
with a more explicit type to enhance type safety.
- let newAchievementMap = {} as Record<HeartEssentialEightScores, boolean>;
+ let newAchievementMap: Record<HeartEssentialEightScores, boolean> = {};
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
function loadScoresFromCustomFieldData( | |
customFieldData: Record<string, string> | |
) { | |
let newScore: number = 0; | |
let newAchievementMap = {} as Record<HeartEssentialEightScores, boolean>; | |
for (const key in props.customFieldDictionary) { | |
if (props.customFieldDictionary[key]) { | |
let surveyScore = customFieldData[props.customFieldDictionary[key]]; | |
let numericScore = parseInt(surveyScore); | |
if (!Number.isNaN(numericScore)) { | |
newScore += numericScore; | |
newAchievementMap[key as HeartEssentialEightScores] = | |
numericScore >= 100; | |
} else { | |
newAchievementMap[key as HeartEssentialEightScores] = false; | |
} | |
} | |
} | |
if (newScore > 0) { | |
newScore = (newScore / 800) * 100; | |
} | |
setScore(parseFloat(newScore.toFixed(1))); | |
setAchievementMap(newAchievementMap); | |
} | |
function loadScoresFromCustomFieldData( | |
customFieldData: Record<string, string> | |
) { | |
let newScore: number = 0; | |
let newAchievementMap: Record<HeartEssentialEightScores, boolean> = {}; | |
for (const key in props.customFieldDictionary) { | |
if (props.customFieldDictionary[key]) { | |
let surveyScore = customFieldData[props.customFieldDictionary[key]]; | |
let numericScore = parseInt(surveyScore); | |
if (!Number.isNaN(numericScore)) { | |
newScore += numericScore; | |
newAchievementMap[key as HeartEssentialEightScores] = | |
numericScore >= 100; | |
} else { | |
newAchievementMap[key as HeartEssentialEightScores] = false; | |
} | |
} | |
} | |
if (newScore > 0) { | |
newScore = (newScore / 800) * 100; | |
} | |
setScore(parseFloat(newScore.toFixed(1))); | |
setAchievementMap(newAchievementMap); | |
} |
return ( | ||
<> | ||
{score === undefined && <LoadingIndicator />} | ||
{score !== undefined && ( | ||
<div> | ||
<div className="mdhui-heart-e8-score-container"> | ||
<ProgressRing | ||
percentCompleted={score} | ||
color="rgb(193, 14, 33)" | ||
children={ | ||
<div className="scoreContainer"> | ||
<div className="score">{score}</div> | ||
<div className="scoreSubText">out of 100</div> | ||
</div> | ||
} | ||
animate={true} | ||
/> | ||
|
||
{achievementMap && ( | ||
<> | ||
<div className="achievementSection"> | ||
<div className="bulletPoint improve" /> | ||
<h4>IMPROVE</h4> | ||
</div> | ||
<div className="achievementIcons"> | ||
{generateAchievementMap(false, achievementMap)} | ||
</div> | ||
<div className="achievementSection"> | ||
<div className="bulletPoint celebrate" /> | ||
<h4>CELEBRATE</h4> | ||
</div> | ||
<div className="achievementIcons"> | ||
{generateAchievementMap(true, achievementMap)} | ||
</div> | ||
</> | ||
)} | ||
</div> | ||
</div> | ||
)} | ||
</> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid using the children
prop directly in JSX.
The ProgressRing
component should use JSX syntax to pass children, as recommended by React best practices.
- <ProgressRing
- percentCompleted={score}
- color="rgb(193, 14, 33)"
- children={
- <div className="scoreContainer">
- <div className="score">{score}</div>
- <div className="scoreSubText">out of 100</div>
- </div>
- }
- animate={true}
- />
+ <ProgressRing percentCompleted={score} color="rgb(193, 14, 33)" animate={true}>
+ <div className="scoreContainer">
+ <div className="score">{score}</div>
+ <div className="scoreSubText">out of 100</div>
+ </div>
+ </ProgressRing>
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
return ( | |
<> | |
{score === undefined && <LoadingIndicator />} | |
{score !== undefined && ( | |
<div> | |
<div className="mdhui-heart-e8-score-container"> | |
<ProgressRing | |
percentCompleted={score} | |
color="rgb(193, 14, 33)" | |
children={ | |
<div className="scoreContainer"> | |
<div className="score">{score}</div> | |
<div className="scoreSubText">out of 100</div> | |
</div> | |
} | |
animate={true} | |
/> | |
{achievementMap && ( | |
<> | |
<div className="achievementSection"> | |
<div className="bulletPoint improve" /> | |
<h4>IMPROVE</h4> | |
</div> | |
<div className="achievementIcons"> | |
{generateAchievementMap(false, achievementMap)} | |
</div> | |
<div className="achievementSection"> | |
<div className="bulletPoint celebrate" /> | |
<h4>CELEBRATE</h4> | |
</div> | |
<div className="achievementIcons"> | |
{generateAchievementMap(true, achievementMap)} | |
</div> | |
</> | |
)} | |
</div> | |
</div> | |
)} | |
</> | |
); | |
return ( | |
<> | |
{score === undefined && <LoadingIndicator />} | |
{score !== undefined && ( | |
<div> | |
<div className="mdhui-heart-e8-score-container"> | |
<ProgressRing percentCompleted={score} color="rgb(193, 14, 33)" animate={true}> | |
<div className="scoreContainer"> | |
<div className="score">{score}</div> | |
<div className="scoreSubText">out of 100</div> | |
</div> | |
</ProgressRing> | |
{achievementMap && ( | |
<> | |
<div className="achievementSection"> | |
<div className="bulletPoint improve" /> | |
<h4>IMPROVE</h4> | |
</div> | |
<div className="achievementIcons"> | |
{generateAchievementMap(false, achievementMap)} | |
</div> | |
<div className="achievementSection"> | |
<div className="bulletPoint celebrate" /> | |
<h4>CELEBRATE</h4> | |
</div> | |
<div className="achievementIcons"> | |
{generateAchievementMap(true, achievementMap)} | |
</div> | |
</> | |
)} | |
</div> | |
</div> | |
)} | |
</> | |
); |
Tools
Biome
[error] 173-173: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
function generateAchievementMap( | ||
didAchieve: boolean, | ||
newAchievementMap: Record<HeartEssentialEightScores, boolean> | ||
) { | ||
const map = newAchievementMap as Record<string, boolean>; | ||
const achievementList: any[] = []; | ||
for (const key in map) { | ||
const vv = map[key]; | ||
if (vv === didAchieve) { | ||
const title = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => { | ||
return str.toUpperCase(); | ||
}); | ||
let icon: any; | ||
let url: string; | ||
const circleClasses: string[] = ["circle"]; | ||
switch (key) { | ||
case "Activity": | ||
icon = iconGetActive; | ||
circleClasses.push("activity"); | ||
break; | ||
case "BloodPressure": | ||
icon = iconManageBloodPressure; | ||
circleClasses.push("bloodPressure"); | ||
break; | ||
case "BloodSugar": | ||
icon = iconReduceBloodSugar; | ||
circleClasses.push("bloodSugar"); | ||
break; | ||
case "BMI": | ||
icon = iconLoseWeight; | ||
circleClasses.push("bmi"); | ||
break; | ||
case "Cholesterol": | ||
icon = iconCholesterol; | ||
circleClasses.push("cholesterol"); | ||
break; | ||
case "Diet": | ||
icon = iconEatWell; | ||
circleClasses.push("diet"); | ||
break; | ||
case "Nicotine": | ||
icon = iconStopSmoking; | ||
circleClasses.push("nicotine"); | ||
break; | ||
case "Sleep": | ||
icon = iconSleep; | ||
circleClasses.push("sleep"); | ||
break; | ||
default: | ||
icon = null; | ||
} | ||
|
||
const achievementIcon = ( | ||
<div className={circleClasses.join(" ")}> | ||
<img src={icon} /> | ||
</div> | ||
); | ||
|
||
const achievement = ( | ||
<div className="actionRow"> | ||
<Action | ||
key={`achievement-${key}`} | ||
title={title} | ||
titleIcon={achievementIcon} | ||
onClick={() => MyDataHelps.openExternalUrl(url)} | ||
/> | ||
</div> | ||
); | ||
achievementList.push(achievement); | ||
} | ||
} | ||
|
||
return achievementList; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enhance type safety and readability.
Consider using more specific types for map
and achievementList
to enhance type safety and readability.
- const map = newAchievementMap as Record<string, boolean>;
- const achievementList: any[] = [];
+ const map: Record<HeartEssentialEightScores, boolean> = newAchievementMap;
+ const achievementList: JSX.Element[] = [];
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
function generateAchievementMap( | |
didAchieve: boolean, | |
newAchievementMap: Record<HeartEssentialEightScores, boolean> | |
) { | |
const map = newAchievementMap as Record<string, boolean>; | |
const achievementList: any[] = []; | |
for (const key in map) { | |
const vv = map[key]; | |
if (vv === didAchieve) { | |
const title = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => { | |
return str.toUpperCase(); | |
}); | |
let icon: any; | |
let url: string; | |
const circleClasses: string[] = ["circle"]; | |
switch (key) { | |
case "Activity": | |
icon = iconGetActive; | |
circleClasses.push("activity"); | |
break; | |
case "BloodPressure": | |
icon = iconManageBloodPressure; | |
circleClasses.push("bloodPressure"); | |
break; | |
case "BloodSugar": | |
icon = iconReduceBloodSugar; | |
circleClasses.push("bloodSugar"); | |
break; | |
case "BMI": | |
icon = iconLoseWeight; | |
circleClasses.push("bmi"); | |
break; | |
case "Cholesterol": | |
icon = iconCholesterol; | |
circleClasses.push("cholesterol"); | |
break; | |
case "Diet": | |
icon = iconEatWell; | |
circleClasses.push("diet"); | |
break; | |
case "Nicotine": | |
icon = iconStopSmoking; | |
circleClasses.push("nicotine"); | |
break; | |
case "Sleep": | |
icon = iconSleep; | |
circleClasses.push("sleep"); | |
break; | |
default: | |
icon = null; | |
} | |
const achievementIcon = ( | |
<div className={circleClasses.join(" ")}> | |
<img src={icon} /> | |
</div> | |
); | |
const achievement = ( | |
<div className="actionRow"> | |
<Action | |
key={`achievement-${key}`} | |
title={title} | |
titleIcon={achievementIcon} | |
onClick={() => MyDataHelps.openExternalUrl(url)} | |
/> | |
</div> | |
); | |
achievementList.push(achievement); | |
} | |
} | |
return achievementList; | |
} | |
function generateAchievementMap( | |
didAchieve: boolean, | |
newAchievementMap: Record<HeartEssentialEightScores, boolean> | |
) { | |
const map: Record<HeartEssentialEightScores, boolean> = newAchievementMap; | |
const achievementList: JSX.Element[] = []; | |
for (const key in map) { | |
const vv = map[key]; | |
if (vv === didAchieve) { | |
const title = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => { | |
return str.toUpperCase(); | |
}); | |
let icon: any; | |
let url: string; | |
const circleClasses: string[] = ["circle"]; | |
switch (key) { | |
case "Activity": | |
icon = iconGetActive; | |
circleClasses.push("activity"); | |
break; | |
case "BloodPressure": | |
icon = iconManageBloodPressure; | |
circleClasses.push("bloodPressure"); | |
break; | |
case "BloodSugar": | |
icon = iconReduceBloodSugar; | |
circleClasses.push("bloodSugar"); | |
break; | |
case "BMI": | |
icon = iconLoseWeight; | |
circleClasses.push("bmi"); | |
break; | |
case "Cholesterol": | |
icon = iconCholesterol; | |
circleClasses.push("cholesterol"); | |
break; | |
case "Diet": | |
icon = iconEatWell; | |
circleClasses.push("diet"); | |
break; | |
case "Nicotine": | |
icon = iconStopSmoking; | |
circleClasses.push("nicotine"); | |
break; | |
case "Sleep": | |
icon = iconSleep; | |
circleClasses.push("sleep"); | |
break; | |
default: | |
icon = null; | |
} | |
const achievementIcon = ( | |
<div className={circleClasses.join(" ")}> | |
<img src={icon} /> | |
</div> | |
); | |
const achievement = ( | |
<div className="actionRow"> | |
<Action | |
key={`achievement-${key}`} | |
title={title} | |
titleIcon={achievementIcon} | |
onClick={() => MyDataHelps.openExternalUrl(url)} | |
/> | |
</div> | |
); | |
achievementList.push(achievement); | |
} | |
} | |
return achievementList; | |
} |
HeartEssentialEight styling
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this file could use an auto format and some TODO cleanup. Let me know once you are done with the revisions here and I'll take another look at it.
} | ||
|
||
export default function (props: HeartEssentialEightProps) { | ||
const customRingStyle: React.CSSProperties = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not appear to be used.
width: "100px", | ||
}; | ||
|
||
let [score, setScore] = React.useState<number>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can just be useState<number>()
. No need for the React
prefix.
|
||
let [score, setScore] = React.useState<number>(); | ||
let [achievementMap, setAchievementMap] = | ||
useState<Record<HeartEssentialEightScores, boolean>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Some of this file appears to be rather "narrow" with regard to formatting. We probably don't need to wrap things quite this aggressively.
let [achievementMap, setAchievementMap] = | ||
useState<Record<HeartEssentialEightScores, boolean>>(); | ||
|
||
async function initialize() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need the async
keyword here. No calls to this function are awaiting or expecting a promise.
|
||
async function initialize() { | ||
if (props.previewState) { | ||
if (["Default", "NoData"].includes(props.previewState ?? "")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't need the ?? ""
here. The includes(...)
function should handle an undefined
preview state without any issues.
loadScoresFromCustomFieldData(data); | ||
} | ||
} else { | ||
MyDataHelps.getParticipantInfo().then((participantInfo) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: No need for the parens around participantInfo
if not specifying a type.
didAchieve: boolean, | ||
newAchievementMap: Record<HeartEssentialEightScores, boolean> | ||
) { | ||
const map = newAchievementMap as Record<string, boolean>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need to do this conversion.
newAchievementMap: Record<HeartEssentialEightScores, boolean> | ||
) { | ||
const map = newAchievementMap as Record<string, boolean>; | ||
const achievementList: any[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be typed as React.JSX.Element[]
.
const map = newAchievementMap as Record<string, boolean>; | ||
const achievementList: any[] = []; | ||
for (const key in map) { | ||
const vv = map[key]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use a more meaningful variable name here?
}); | ||
let icon: any; | ||
let subtitle: any; | ||
let url: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't look like the URL variable ever gets set. Are we still deciding what to do with these actions when clicked?
title={title} | ||
subtitle={subtitle} | ||
icon={achievementIcon} | ||
onClick={() => MyDataHelps.openExternalUrl(url)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may want to have this call a handler function on the props. That way, when this is added to the view builder, it can use an ActionDefinition
setting to allow the person building the view to configure what happens when each of the types is clicked. Maybe it opens a URL, launches another app, or goes to a different tab, etc.
If we go that route, we'd probably want to support configurable subtitle text for each action as well.
.mdhui-heart-e8-achievement-container .le8-header { | ||
margin: var(--mdhui-padding-sm) 0 var(--mdhui-padding-xs) 0; | ||
} | ||
.achievementActionList { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you will probably want to prefix all these classes with mdhui-heart-e8-
to avoid any potential collisions.
<h3 className="le8-header">Heart Health Score</h3> | ||
<ProgressRing | ||
percentCompleted={score} | ||
color="rgb(193, 14, 33)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this use one of the existing color variables?
<> | ||
<Card> | ||
<div className="mdhui-heart-e8-score-container"> | ||
<h3 className="le8-header">Heart Health Score</h3> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can use <Title order={3}>Heart Health Score</Title>
for these, perhaps with a custom margin, if that remains necessary.
switch (key) { | ||
case "Activity": | ||
icon = iconGetActive; | ||
subtitle="Display Active Time from Fitbit / Garmin. Probably AppleExerciseTime for Apple Health. Or manual entry"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just putting a note here as a reminder to localize all the hard coded text once the design gets finalized.
|
||
const render = (args: HeartEssentialEightProps) => { | ||
return ( | ||
<Layout colorScheme="auto"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider setting up the story to allow for swapping between color schemes for easier review of light/dark/auto modes.
Similarly, the preview state can be set up as a toggle on a single story if you'd like.
Overview
Heart Essential 8 component.
Mobile friendly view. Hoping to get some eyes on for next steps.
Security
REMINDER: All file contents are public.
Describe briefly what security risks you considered, why they don't apply, or how they've been mitigated.
Checklist
Testing
Documentation
Consider "Squash and merge" as needed to keep the commit history reasonable on
main
.Reviewers
Assign to the appropriate reviewer(s). Minimally, a second set of eyes is needed ensure no non-public information is published. Consider also including:
Summary by CodeRabbit
Summary by CodeRabbit
New Features
Documentation