Skip to content

Implement like heart feature and AI feedback context#26

Open
SeunFashina002 wants to merge 6 commits intoTopFlight-Digital:masterfrom
SeunFashina002:feature/like-heart-ai-feedback
Open

Implement like heart feature and AI feedback context#26
SeunFashina002 wants to merge 6 commits intoTopFlight-Digital:masterfrom
SeunFashina002:feature/like-heart-ai-feedback

Conversation

@SeunFashina002
Copy link
Collaborator

🚀 Feature: Like Heart & AI Feedback Context

Summary

This PR implements the "like heart" feature for hypotheses (A/B test ideas) and enhances idea generation by sending liked ideas as context to the AI, as outlined in the project roadmap.

What’s Included

  • Like Heart Feature:
    • Users can mark their favorite hypotheses with a heart icon.
    • Liked ideas are persisted in localStorage and remain visible after re-scans or feedback.
  • AI Feedback Context:
    • When generating new ideas or sending feedback, all liked ideas are sent to the backend.
    • The backend includes these liked ideas in the prompt to the AI, so new suggestions are more tailored to user preferences.
  • Robustness:
    • Defensive checks to prevent runtime errors if localStorage is corrupted or missing.
    • TypeScript and linter fixes related to the new feature.

How It Works

  1. Users can like/unlike any hypothesis card.
  2. Liked ideas persist across sessions and re-scans.
  3. When the user requests new ideas or gives feedback, their liked ideas are included in the AI prompt for more relevant suggestions.

Why This Matters

  • Personalizes the user experience by letting users influence future suggestions.
  • Aligns with the roadmap for improved idea generation and user engagement.

Notes

  • This PR only changes what’s necessary for the feature and related bug fixes.
  • Other unrelated linter/type issues are left for future PRs.

Copy link
Contributor

@v1olen v1olen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've found so nice-to-fix bits, reckon there's a few more things that would be good to tweak but the formatter thing (I've mentioned in the comment) make it harder to review. Would be nice if you could get rid of this formatting changes so I can do a second round later :)

title: string;
description: string;
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that you have some extra linter (like prettier or sth else) enabled, could you disable it for this project? There's a lot of formatting changes in this PR that will probably get reverted when other person will work on these files; it'll lead to battle of linters leaving post-battle wrecks in every PR 😄

We use eslint for code formatting (planning to migrate to stylistic in the future), feel free to run it from cli on the entire codebase at the very end and keep in a separate commit, then just enable it in your IDE

@@ -0,0 +1,2900 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally use pnpm, rather than npm. Let's don't keep two types of lock files in the codebase

vite.config.ts Outdated
export default defineConfig({
define: {
API_SERVER_URL: JSON.stringify(``),
API_SERVER_URL: JSON.stringify(`http://localhost:4000`),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to finally split it to .env file, but up to you, we can also do it later

Comment on lines 46 to 74
<svg
v-if="props.liked"
width="24"
height="24"
viewBox="0 0 24 24"
fill="white"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41 0.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"
/>
</svg>
<svg
v-else
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="white"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41 0.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"
/>
</svg>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move the icon to a separate component

:index="index + 1"
:title="item.title"
:subtitle="item.description"
:liked="isLiked(item.title)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember atm but don't we have any more suitable field to identify a single hypothesis by?

Comment on lines 59 to 62
// If currently liked, remove from Map (unlike)
likedHypotheses.value.delete(title);
} else {
// If not liked, set to true (like)
Copy link
Contributor

@v1olen v1olen Jun 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you think this code here is pretty self-explanatory? We usually stick to a rule that "comments are apologies", while this piece of code doesn't need to apologise, these comment seem to be typical this-is-a-stop-sign comments 😄

Comment on lines 46 to 47
read: (v) => new Map(JSON.parse(v || "[]")),
write: (v) => JSON.stringify(Array.from(v.entries())),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually try to not use single letters to name variables

);

function isLiked(title: string) {
return likedHypotheses.value.get(title) === true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return likedHypotheses.value.get(title) === true;
return likedHypotheses.value.get(title);

Comment on lines 460 to 462
const prev = (bloc.hypotheses || []).find(
(h: Hypothesis) => h.title === title,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually try to not use single letters or abbrs to name variables

Comment on lines 448 to 464
const missingLiked = (
JSON.parse(localStorage.getItem("liked.hypotheses") || "[]") as [
string,
boolean,
][]
)
.filter(
([title, liked]) =>
liked && !results.some((h: Hypothesis) => h.title === title),
)
.map(([title]) => {
// Try to find the last known version in previous hypotheses
const prev = (bloc.hypotheses || []).find(
(h: Hypothesis) => h.title === title,
);
return prev || { title, description: "(Previously liked idea)" };
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though it's possible to understand, would be good to decrease a cognitive load needed to do so 😄

Could you replace it with an easy-to-read procedural logic based on for..of loop?

@SeunFashina002
Copy link
Collaborator Author

SeunFashina002 commented Jun 20, 2025 via email

@v1olen
Copy link
Contributor

v1olen commented Jun 20, 2025

Saw a comment @v1olen where you asked if the pr contains generation of tailors ideas based on the liked idea. I can't find the comment again, but yeah, it does.

Yea, I see, I missed that and therefore removed the comment. All good, thanks :)

@SeunFashina002
Copy link
Collaborator Author

SeunFashina002 commented Jun 20, 2025

Will work on all the changes you mentioned @v1olen , and yeah, I will get rid of that formatter 😅. Sorry about that!

@SeunFashina002 SeunFashina002 force-pushed the feature/like-heart-ai-feedback branch from d06e7ad to e8d6e61 Compare June 23, 2025 11:52
@SeunFashina002
Copy link
Collaborator Author

@v1olen I've made changes to the code blocks you highlighted. As for the formatter, I've disabled prettier and I tried using lint:fix to force my code to follow the rules specified in the .eslintrc file before pushing this time. Does that help in any way to review smoothly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants