-
Notifications
You must be signed in to change notification settings - Fork 0
finishing: Mvp/kopi maker #5 #7
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
Conversation
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.
Pull request overview
This PR implements a complete redesign of the Kopi Maker tab, transforming it from a placeholder into a fully functional kopi customization interface. The implementation introduces a Zustand-based state management system, new reusable UI components, and a visually distinctive two-section layout with a custom SVG curve separator. The PR also includes necessary cleanup by removing unused template components and updating documentation.
Key Changes:
- Implemented interactive kopi customization UI with state management (Zustand store, utility functions, type definitions)
- Created reusable components (KopiCupPreview, OptionSelector) with NativeWind styling
- Added new color tokens (cream, warm-beige, accent) across theme system
- Removed unused template components (modal, parallax-scroll-view, external-link, hello-wave)
Reviewed changes
Copilot reviewed 17 out of 19 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
app/(tabs)/kopi.tsx |
Main screen redesign with preview section, option selectors, SVG curve divider, and brew button |
stores/kopiMakerStore.ts |
Zustand store managing kopi selection state (milkiness, sweetness, strength, temperature) with derived helpers |
utils/kopiInfer.ts |
Utility functions mapping kopi selections to display names and order phrases |
types/kopi.ts |
Type definitions for kopi options, selections, and UI option items |
components/kopi/KopiCupPreview.tsx |
Preview component displaying selected kopi name with curved bottom border |
components/kopi/OptionSelector.tsx |
Reusable option selector component with Pressable buttons |
components/kopi/index.ts |
Component exports barrel file |
constants/theme.ts |
Added cream, warmBeige, and accent colors to palette |
global.css |
Added CSS variables for new colors |
tailwind.config.js |
Extended Tailwind color configuration |
package.json |
Added react-native-svg dependency |
pnpm-lock.yaml |
Lockfile updates for new dependencies |
AGENTS.md |
Updated documentation with current architecture |
app/modal.tsx |
Removed unused modal component |
app/_layout.tsx |
Removed modal route registration |
components/parallax-scroll-view.tsx |
Removed unused template component |
components/hello-wave.tsx |
Removed unused template component |
components/external-link.tsx |
Removed unused template component |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // 关键:往下压 CURVE_DEPTH,让“曲线边”贴在分界处 | ||
| bottom: -CURVE_DEPTH, | ||
| zIndex: 999, | ||
| elevation: 999, // 安卓需要 |
Copilot
AI
Nov 23, 2025
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 inline comment is in Chinese. Code comments should be in English for consistency and accessibility.
Suggestion: Replace with an English comment like:
elevation: 999, // Needed for Android| elevation: 999, // 安卓需要 | |
| elevation: 999, // Needed for Android |
| import { Dimensions, Pressable, ScrollView, Text, View } from "react-native"; | ||
| import Svg, { Path } from "react-native-svg"; | ||
|
|
||
| const { width } = Dimensions.get("window"); | ||
| const CURVE_HEIGHT = 80; | ||
| const CURVE_DEPTH = 50; | ||
| const SVG_H = CURVE_HEIGHT + CURVE_DEPTH; | ||
|
|
||
| export default function KopiScreen() { |
Copilot
AI
Nov 23, 2025
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.
Calling Dimensions.get("window") at module level can cause issues during initial render and doesn't respond to dimension changes (e.g., device rotation, window resize on web).
Recommendation: Move this inside the component and use useState with an effect to handle dimension changes, or use useWindowDimensions() hook from React Native:
import { useWindowDimensions } from 'react-native';
export default function KopiScreen() {
const { width } = useWindowDimensions();
// ... rest of code| import { Dimensions, Pressable, ScrollView, Text, View } from "react-native"; | |
| import Svg, { Path } from "react-native-svg"; | |
| const { width } = Dimensions.get("window"); | |
| const CURVE_HEIGHT = 80; | |
| const CURVE_DEPTH = 50; | |
| const SVG_H = CURVE_HEIGHT + CURVE_DEPTH; | |
| export default function KopiScreen() { | |
| import { Pressable, ScrollView, Text, View, useWindowDimensions } from "react-native"; | |
| import Svg, { Path } from "react-native-svg"; | |
| const CURVE_HEIGHT = 80; | |
| const CURVE_DEPTH = 50; | |
| const SVG_H = CURVE_HEIGHT + CURVE_DEPTH; | |
| export default function KopiScreen() { | |
| const { width } = useWindowDimensions(); |
| import { Dimensions, Text, View } from 'react-native'; | ||
|
|
||
| interface KopiCupPreviewProps { | ||
| name: string; | ||
| } | ||
|
|
||
| const { width } = Dimensions.get('window'); | ||
| const curveRadius = width; // big radius to form a smooth smile at the bottom edge | ||
|
|
||
| export const KopiCupPreview = ({ name }: KopiCupPreviewProps) => { |
Copilot
AI
Nov 23, 2025
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.
Similar to the main Kopi screen, calling Dimensions.get("window") at module level doesn't respond to dimension changes and can cause layout issues during rotation or window resize.
Recommendation: Use useWindowDimensions() hook inside the component:
import { useWindowDimensions, Text, View } from 'react-native';
export const KopiCupPreview = ({ name }: KopiCupPreviewProps) => {
const { width } = useWindowDimensions();
const curveRadius = width;
// ... rest of code| import { Dimensions, Text, View } from 'react-native'; | |
| interface KopiCupPreviewProps { | |
| name: string; | |
| } | |
| const { width } = Dimensions.get('window'); | |
| const curveRadius = width; // big radius to form a smooth smile at the bottom edge | |
| export const KopiCupPreview = ({ name }: KopiCupPreviewProps) => { | |
| import { useWindowDimensions, Text, View } from 'react-native'; | |
| interface KopiCupPreviewProps { | |
| name: string; | |
| } | |
| export const KopiCupPreview = ({ name }: KopiCupPreviewProps) => { | |
| const { width } = useWindowDimensions(); | |
| const curveRadius = width; // big radius to form a smooth smile at the bottom edge |
| <View className="absolute bottom-8 left-0 right-0 px-6"> | ||
| <Pressable | ||
| className="bg-dark-coffee py-4 rounded-2xl items-center shadow-lg active:opacity-90" | ||
| onPress={() => console.log("Brewing:", phrase)} |
Copilot
AI
Nov 23, 2025
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.
The "Brew" button lacks accessibility properties, which makes it less accessible to users with screen readers.
Recommendation: Add accessibilityLabel and accessibilityRole:
<Pressable
className="bg-dark-coffee py-4 rounded-2xl items-center shadow-lg active:opacity-90"
onPress={() => console.log("Brewing:", phrase)}
accessibilityLabel={`Brew ${phrase}`}
accessibilityRole="button"
>| onPress={() => console.log("Brewing:", phrase)} | |
| onPress={() => console.log("Brewing:", phrase)} | |
| accessibilityLabel={`Brew ${phrase}`} | |
| accessibilityRole="button" |
|
|
||
| ## State & Domain | ||
| - Zustand store `stores/kopiMakerStore.ts`: holds kopi selection (`milkiness`, `sweetness`, `strength`, `temperature`), setters/reset, derived `baseName/displayName/phrase` via `utils/kopiInfer`. | ||
| - Domain types `types/kopi.ts`: option groups, option lists, `KopiSelection`, default selection. Temperature replaces earlier “state” naming. |
Copilot
AI
Nov 23, 2025
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 sentence is unclear: "Temperature replaces earlier 'state' naming." This seems to reference previous code state that reviewers cannot see, making the documentation confusing for someone new to the codebase.
Recommendation: Either clarify what this means or remove this historical reference:
- Domain types `types/kopi.ts`: option groups, option lists, `KopiSelection`, default selection.| - Domain types `types/kopi.ts`: option groups, option lists, `KopiSelection`, default selection. Temperature replaces earlier “state” naming. | |
| - Domain types `types/kopi.ts`: option groups, option lists, `KopiSelection`, default selection. |
| /** | ||
| * Hook to access Kopi Maker store. | ||
| * | ||
| * State: | ||
| * - milkiness, sweetness, strength, temperature | ||
| * | ||
| * Actions: | ||
| * - setMilkiness, setSweetness, setStrength, setTemperature, reset | ||
| * | ||
| * Derived helpers: | ||
| * - baseName, displayName, phrase | ||
| */ |
Copilot
AI
Nov 23, 2025
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.
[nitpick] The JSDoc comment block has inconsistent formatting. Lines 81 and 84 have misaligned asterisks that don't align with the rest of the comment block structure.
Suggestion: Align all asterisks consistently:
/**
* Hook to access Kopi Maker store.
*
* State:
* - milkiness, sweetness, strength, temperature
*
* Actions:
* - setMilkiness, setSweetness, setStrength, setTemperature, reset
*
* Derived helpers:
* - baseName, displayName, phrase
*/| <View className="absolute bottom-8 left-0 right-0 px-6"> | ||
| <Pressable | ||
| className="bg-dark-coffee py-4 rounded-2xl items-center shadow-lg active:opacity-90" | ||
| onPress={() => console.log("Brewing:", phrase)} |
Copilot
AI
Nov 23, 2025
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.
There's a console.log statement in the production code. While this might be a placeholder for future functionality, console logs should generally be removed from production code or replaced with proper logging/handling.
Recommendation: Either implement the actual brew functionality or remove the console log and add a TODO comment:
onPress={() => {
// TODO: Implement brew functionality
}}| onPress={() => console.log("Brewing:", phrase)} | |
| onPress={() => { | |
| // TODO: Implement brew functionality | |
| }} |
| hint?: string; // optional, local term or explanation, e.g., "(Gao)" | ||
| }; | ||
|
|
||
| /* 6) Four groups of UI options (directly used for Picker map rendering) */ |
Copilot
AI
Nov 23, 2025
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.
The comment starts with "6)" but there's no numbered list context (no items 1-5 visible). This suggests either:
- Previous numbered items were removed, or
- This is a copy-paste artifact
Recommendation: Remove the number prefix:
/* Four groups of UI options (used for rendering option selectors) */| /* 6) Four groups of UI options (directly used for Picker map rendering) */ | |
| /* Four groups of UI options (directly used for Picker map rendering) */ |
| <View style={{ flex: 0.4, zIndex: 2, backgroundColor: topBg }}> | ||
| <KopiCupPreview name={phrase} /> | ||
|
|
||
| {/* 微笑曲线分界 */} |
Copilot
AI
Nov 23, 2025
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 comment is in Chinese. Code comments should be in English for consistency and accessibility.
Suggestion: Replace with an English comment like:
{/* Smile curve divider */}| {/* 微笑曲线分界 */} | |
| {/* Smile curve divider */} |
| position: "absolute", | ||
| left: 0, | ||
| right: 0, | ||
| // 关键:往下压 CURVE_DEPTH,让“曲线边”贴在分界处 |
Copilot
AI
Nov 23, 2025
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 inline comment is in Chinese. Code comments should be in English for consistency and accessibility.
Suggestion: Replace with an English comment like:
// Key: Push down by CURVE_DEPTH so the "curve edge" aligns at the boundary| // 关键:往下压 CURVE_DEPTH,让“曲线边”贴在分界处 | |
| // Key: Push down by CURVE_DEPTH so the "curve edge" aligns at the boundary |

This pull request introduces a major refactor and redesign of the Kopi Maker tab, focusing on improved UI, state management, and codebase cleanup. It removes unused components and modal functionality, introduces new UI components for kopi customization, and updates the documentation and dependencies to reflect these changes.
Kopi Maker UI and State Redesign:
app/(tabs)/kopi.tsx) is rebuilt with a two-section layout: a preview area and interactive option selectors for milk, sugar, strength, and temperature, powered by a Zustand store. A custom SVG curve visually separates sections, and a "Brew" button is added. ([app/(tabs)/kopi.tsxL1-R111](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-f78a2a8d52ae26b5d252e01225fa3864692bb07f55d4ecf0c1cd789224736e29L1-R111))KopiCupPreviewfor displaying the selected kopi name, andOptionSelectorfor user selection of kopi options. ([[1]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-11fffcf876611b227a744028ffcea9b497fb5c854c43d6139cc60ce5849b6f9aR1-R26),[[2]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-0c7d038ed3a4687ae63226f3770c9cddde5081f89de7ed6438f2f9224c8cad69R1-R50),[[3]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-c78dee33b05b07063fc2e0dafd39a752a11f0a430d3ac29331075059afb9b2a7R1-R2))[[1]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-e266bec56ac932c8c0a110dbe572b7552bf0ca146d5033572074018d1b61033aR17-R20),[[2]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-c3a392bca08e12a4456b4e08e3900540c977d5f83fe9da4925b0538e354342fcR12-R14))Codebase Cleanup and Removal of Unused Components:
hello-wave,parallax-scroll-view,external-link, and themed text/view). ([[1]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-2e642ecf25da57eeaadd6bbed731ce44ff428a12b9448aac88a196a0d840de4fL1-L29),[[2]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-a297596ca5a79abd3db7509592a07106f1c27c02ee55895a4dee8bcce9f7da57L19),[[3]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-bb410e30d8c9af736088170f7e2dd151f91fae55e890550b446039fd5aa5403bL1-L19),[[4]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-6f16362f0746e762c9f020d6b9a495af5adeb4b080fd05d807e426399786a053L1-L79),[[5]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-0d36e81c07fa81fd53e0226d4e9fab2e5eeae508ad1f0f30a150bdad4a8791c3L1-L25))Documentation and Tooling Updates:
AGENTS.mdto document the new UI architecture, state management, and styling approach, replacing the previous technical summary. ([[1]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9R1-R28),[[2]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-4244d88adfe5757005318fe9a46f631ada97796532af355e25fe504c2bc6df57L1-L28))react-native-svgas a new dependency for custom SVG rendering in the UI, updating bothpackage.jsonand lockfile. ([[1]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519R38),[[2]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-32824c984905bb02bc7ffcef96a77addd1f1602cff71a11fbbfdd7f53ee026bbL61-R61),[[3]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-32824c984905bb02bc7ffcef96a77addd1f1602cff71a11fbbfdd7f53ee026bbR83-R85))pnpm-lock.yaml) updated for new and removed dependencies. ([[1]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-32824c984905bb02bc7ffcef96a77addd1f1602cff71a11fbbfdd7f53ee026bbL61-R61),[[2]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-32824c984905bb02bc7ffcef96a77addd1f1602cff71a11fbbfdd7f53ee026bbR83-R85),[[3]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-32824c984905bb02bc7ffcef96a77addd1f1602cff71a11fbbfdd7f53ee026bbR1696-R1698),[[4]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-32824c984905bb02bc7ffcef96a77addd1f1602cff71a11fbbfdd7f53ee026bbR1896-R1906),[[5]](https://github.com/Boxuan-Matty-Lin/kopi-shop/pull/7/files#diff-32824c984905bb02bc7ffcef96a77addd1f1602cff71a11fbbfdd7f53ee026bbR2012-R2024))These changes modernize the Kopi tab, streamline the codebase, and set up a more maintainable and extensible foundation for future development.