Skip to content

feat: emoji suggestion via Gemini AI and theme cycle toggle#26

Open
guid3d wants to merge 18 commits into
developfrom
feat/emoji-suggestion
Open

feat: emoji suggestion via Gemini AI and theme cycle toggle#26
guid3d wants to merge 18 commits into
developfrom
feat/emoji-suggestion

Conversation

@guid3d

@guid3d guid3d commented May 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add AI emoji suggestion feature: new /api/emoji-suggest route calls Gemini 2.5 Flash Lite to suggest 5 emojis based on group/transaction name; useEmojiSuggestions hook debounces requests (400ms) and auto-applies first suggestion to avatar field
  • EmojiActionButton gains cycle button (↻) to rotate through AI suggestions; shows loader while fetching; manual picker pick overrides AI suggestions
  • Theme toggle now cycles light → dark → auto (with IconBrightnessAutoFilled), replacing binary light/dark flip
  • Fix: participants can be added without typing IBAN; optimize emoji randomizer; add save button loading indicator; fix TS errors blocking prod build

Test plan

  • Create group/transaction — AI emoji suggestions appear and auto-fill avatar
  • Cycle button rotates through 5 AI suggestions
  • Manually picking from picker overrides AI suggestion (cycle button hidden)
  • Theme toggle cycles light → dark → auto → light
  • Add participant without IBAN works
  • Production build passes (npm run build)

🤖 Generated with Claude Code

guid3d and others added 7 commits May 17, 2026 19:16
Raise tsconfig target es5→es2015: Intl.Segmenter spread and /u regex
flag both require ES2015+. Fix useRef missing initial value for React 19
strict types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- UserDropdown and ToggleDarkLightMode cycle light→dark→auto instead
  of toggling light↔dark only; uses stored colorScheme not computed
- TabTransactions uses useComputedColorScheme so indicator color
  renders correctly when scheme is "auto"
- MantineProvider gets defaultColorScheme="auto" to follow OS pref

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
splt Ready Ready Preview, Comment May 18, 2026 1:51pm

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds AI-backed emoji suggestions and updates theme cycling behavior, alongside participant/payment and UI refinements.

Changes:

  • Adds Gemini-based emoji suggestion API and client hook integration for transaction avatars.
  • Updates theme toggles to cycle through light, dark, and auto.
  • Adjusts participant avatar/payment behavior and trims the random emoji pools.

Reviewed changes

Copilot reviewed 13 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tsconfig.json Raises TypeScript target to ES2015.
src/utils/randomEmoji.ts Replaces large emoji lists with curated pools.
src/hooks/useEmojiSuggestions.ts Adds debounced emoji suggestion fetching hook.
src/components/UserSelectionModal.tsx Adds dotted loader style to save button.
src/components/UserDropdown.tsx Changes theme menu item to cycle light/dark/auto.
src/components/ToggleDarkLightMode.tsx Updates standalone theme toggle to cycle modes.
src/components/EmojiActionButtion.tsx Adds AI suggestion auto-apply, loader, and cycle/randomize button.
src/components/AddParticipantModal/index.tsx Allows blank IBAN during participant creation.
src/components/AddParticipantModal/components/PageSetPayment.tsx Adds participant avatar randomization callback.
src/components/AddEditTransactionModal/components/PageSetDetails.tsx Wires transaction name into emoji suggestions.
src/app/layout.tsx Sets Mantine provider default color scheme to auto.
src/app/group/[groupId]/components/TabTransactions.tsx Uses computed color scheme for transaction indicators.
src/app/api/emoji-suggest/route.ts Adds Gemini-backed emoji suggestion endpoint.
package.json Adds Google Generative AI dependency.
package-lock.json Locks Google Generative AI dependency.
Comments suppressed due to low confidence (4)

src/app/api/emoji-suggest/route.ts:20

  • The response parser treats any segment with the Unicode Emoji property as a suggestion, but that property also includes digits and some symbols. If the model returns a numbered list despite the prompt, values like 1 or 2 can be returned as “emojis” ahead of the actual emoji suggestions.
  const emojis = [...new Intl.Segmenter().segment(text)]
    .map((s) => s.segment)
    .filter((s) => /\p{Emoji}/u.test(s) && s !== " ")
    .slice(0, 5);

src/app/api/emoji-suggest/route.ts:15

  • Gemini failures are not handled, so a missing API key, quota error, model error, or transient network failure will surface as a 500 from this route. Since the UI treats suggestions as optional, the API should return a controlled empty/error response instead of failing the request.
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash-lite" });
  const result = await model.generateContent(
    `Given the transaction name: "${name}", suggest 5 relevant emojis. Reply with ONLY the 5 emojis separated by spaces, nothing else. No words, no punctuation, just emojis.`
  );

src/app/api/emoji-suggest/route.ts:14

  • There is no type or length validation for name before it is interpolated into the Gemini prompt. A malformed or very large JSON value can produce server errors or unnecessarily large/expensive model requests; constrain this to a string with a reasonable maximum length before calling the model.
  const { name } = await req.json();
  if (!name?.trim()) return NextResponse.json({ emojis: [] });

  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash-lite" });
  const result = await model.generateContent(
    `Given the transaction name: "${name}", suggest 5 relevant emojis. Reply with ONLY the 5 emojis separated by spaces, nothing else. No words, no punctuation, just emojis.`

src/hooks/useEmojiSuggestions.ts:20

  • This starts sending transaction names to the server/Gemini automatically as the user types. Expense names can contain sensitive personal information, so this should be opt-in or otherwise clearly disclosed/controlled before forwarding user-entered data to a third-party AI service.
        const res = await fetch("/api/emoji-suggest", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ name: query }),

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/app/api/emoji-suggest/route.ts Outdated
Comment thread src/hooks/useEmojiSuggestions.ts
Comment thread src/components/EmojiActionButtion.tsx
Comment thread src/components/AddParticipantModal/index.tsx
</Center>
<Center>
<EmojiActionButtion form={form} />
<EmojiActionButtion form={form} suggestionQuery={form.values.name} />
Comment thread src/utils/randomEmoji.ts
…a abuse

- Sanitize user input before prompt interpolation to prevent injection
- Add IP-based rate limiting (20 req/min) with auto-expiry cleanup
- Use Extended_Pictographic to filter emoji response, avoiding digit false positives
- Wrap Gemini call in try/catch for graceful error handling
- Fall back to curated expense emojis when suggestions unavailable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 16 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

src/app/api/emoji-suggest/route.ts:41

  • This guard assumes name is a string before the later String(name) normalization. A public caller can send a non-string JSON value (for example a number or object), causing name?.trim to throw outside the try block and return a 500.
  const { name } = await req.json();
  if (!name?.trim()) return NextResponse.json({ emojis: [] });

Comment thread src/hooks/useEmojiSuggestions.ts
</Center>
<Center>
<EmojiActionButtion form={form} />
<EmojiActionButtion form={form} suggestionQuery={form.values.name} />

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Implemented in commit 3d1db6c.

The transaction details page now only passes suggestionQuery in create mode, so edit mode no longer triggers auto-apply from AI suggestions and existing avatars are preserved unless explicitly changed.

Screenshot: behavior-only fix (no visual UI change in this update).

Comment thread src/components/EmojiActionButtion.tsx
Comment thread src/app/api/emoji-suggest/route.ts
Comment thread src/components/EmojiActionButtion.tsx
Comment thread src/utils/randomEmoji.ts
// Nature & weather
"🌈", "🌊", "🌋", "🌍", "🌙", "🌞", "🌟", "🌸", "🌺", "🌻", "🌼", "🍀",
"🍁", "🍂", "🍃", "🌿", "🌵", "🌴", "🌲", "🌳", "⛄", "❄️", "🔥", "💧",
"🌧️", "⛅", "🌤️", "🌪️", "🌈", "☀️",
Comment thread src/app/api/emoji-suggest/route.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
guid3d and others added 4 commits May 18, 2026 09:42
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI commented May 18, 2026

Copy link
Copy Markdown
Contributor

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Copilot AI commented May 18, 2026

Copy link
Copy Markdown
Contributor

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Copilot finished work on behalf of guid3d May 18, 2026 07:51
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@guid3d

guid3d commented May 18, 2026

Copy link
Copy Markdown
Owner Author

@copilot build fail from vercel, fix it

Copilot AI commented May 18, 2026

Copy link
Copy Markdown
Contributor

@copilot build fail from vercel, fix it

Fixed in commit 810ea22.

I investigated CI runs and reproduced locally: the emoji-suggest route imports @upstash/redis and @upstash/ratelimit, but those packages were not declared in package.json, which can break Vercel builds. I added both dependencies and updated the lockfile.

Validation after the fix: npm run build succeeds.

@guid3d

guid3d commented May 18, 2026

Copy link
Copy Markdown
Owner Author

@copilot somehow when emoji suggestion when typing in group name is wrong unlike how it was before

Copilot AI commented May 18, 2026

Copy link
Copy Markdown
Contributor

@copilot somehow when emoji suggestion when typing in group name is wrong unlike how it was before

Fixed in commit e650167.

I restored the previous auto-apply behavior for AI suggestions in group creation, so typing the group name now updates the avatar from the first fresh suggestion again (unless manually set in picker).

Screenshot (behavior-only change):
Group emoji suggestion behavior fix

@guid3d

guid3d commented May 18, 2026

Copy link
Copy Markdown
Owner Author

@copilot revert all the change to fab046d

Agent-Logs-Url: https://github.com/guid3d/splt/sessions/28314fb0-08ae-48c1-8032-fe5c38a23099

Co-authored-by: guid3d <29707419+guid3d@users.noreply.github.com>

Copilot AI commented May 18, 2026

Copy link
Copy Markdown
Contributor

@copilot revert all the change to fab046d

Done in commit 59b2378.

I reverted all post-fab046d83c3744fceffaba9ddebe4e43f7c61dc6 changes by restoring the touched files to that baseline state.

Screenshot:

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.

3 participants