Skip to content

[DON'T MERGE] [OC-67] ✨ feat: 折り紙難易度表示機能とラベル表示機能の実装#27

Open
YutaK1026 wants to merge 12 commits into
mainfrom
OC-67
Open

[DON'T MERGE] [OC-67] ✨ feat: 折り紙難易度表示機能とラベル表示機能の実装#27
YutaK1026 wants to merge 12 commits into
mainfrom
OC-67

Conversation

@YutaK1026
Copy link
Copy Markdown
Contributor

@YutaK1026 YutaK1026 commented Aug 30, 2025

タイトル

概要

  • 折り紙難易度機能を星として右上に表示
  • ラベルを折り紙の下に表示されるようにした

変更内容

スクリーンショット

スクリーンショット 2025-08-31 0 57 06

備考

現状はDB変更しなくてもエラー吐かないように追加props部分はオプショナルにしているけど,今後のためにDBの変更・seedの変更をしないといけないね.

@notion-workspace
Copy link
Copy Markdown

@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 30, 2025

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

Project Deployment Preview Comments Updated (UTC)
ori-cube Ready Ready Preview Comment Oct 27, 2025 1:31am

@YutaK1026 YutaK1026 changed the title ✨ feat: 折り紙難易度表示機能とラベル表示機能の実装【OC-67】 [OC-67] ✨ feat: 折り紙難易度表示機能とラベル表示機能の実装 Aug 30, 2025
@YutaK1026 YutaK1026 requested a review from yutteee August 30, 2025 15:52
@YutaK1026 YutaK1026 self-assigned this Aug 30, 2025
@YutaK1026 YutaK1026 requested a review from akaishikiso August 30, 2025 15:52
akaishikiso
akaishikiso previously approved these changes Sep 28, 2025
Copy link
Copy Markdown
Contributor

@akaishikiso akaishikiso left a comment

Choose a reason for hiding this comment

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

\いくつかコメントしましたが、CI通るようになってたらOKです/
lgtm-gif

id,
name,
imageUrl,
difficulty = 1, // デフォルト値1を設定
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.

[imo]難易度未設定の場合はゼロ値を入れて、何も情報がないことがわかるほうがいい気がしました!(誤った情報になりうるため)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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


return (
<Link href={{ pathname: `/${id}` }} className={styles.listItem}>
<div className={styles.difficultyStars}>{renderStars()}</div>
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.

[imo]こんな感じでラベルを添えてあげたほうが、何の星かわかるので優しい気がしました!

スクリーンショット 2025-09-28 16 20 20

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

ここにはロジックのテストを書きたいです。
UIがPropsによって意図した通りに表示されるかどうかというのは、ロジックで書くものではなく、ChromaticなどのVRTで実装すべきです。(作ってないですが...)

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.

Frontendの単体テストの対象はロジックであることが一般的です。
例えば以下のテストだと、どこまでをテストできてると言えるでしょうか?

  it("タグが正しく表示される", () => {
    render(<OrigamiListItem {...mockModel} />);

    expect(screen.getByText("初心者向け")).toBeInTheDocument();
    expect(screen.getByText("楽しい")).toBeInTheDocument();
  });

DOMの中に"初心者向け"と"楽しい"というテキストが含まれているかしか見れません。
例えばvisually: hiddenが付いてて画面に表示されてないとか、予期せぬ場所にレンダリングされてるとか、UI観点でのテストはカバーされてないです。

コードを見るとただ渡されたPropsを表示しているだけなので、このテストを毎回書くと工数がかかる割に得られる効果は少ないです。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🩹 update: PR修正対応: ゆってぃーのFEテストの指摘点を反映

UIテストあんまり詳しくないから勉強になるっす.
ロジックテストになるように考えて,AIに書いてもらっています.
ベストプラクティスではないかも...

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.

結論から言えば、これらのテストは全て不要だと思います。
このコンポーネント自体、ロジックは持っていないからです。

propsが渡されて、それをそのままレンダリングしてるだけですよね。(altとかlinkとか特に)
どういう見た目になるかとか、それはstorybookで書いてるので重複したコードになってます。

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.

強いて言えば、星のテストの部分はあってもなくてもいいかなくらいの認識です。

Comment on lines +21 to +35
const renderStars = () => {
const stars = [];
for (let i = 1; i <= 5; i++) {
const isFilled = i <= difficulty;
stars.push(
<FaStar
key={i}
className={`${styles.star} ${
isFilled ? styles.filled : styles.empty
}`}
/>
);
}
return stars;
};
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.

reactではあまりdomを直接操作する書き方はしないかな...
https://ja.react.dev/reference/rules/react-calls-components-and-hooks#never-call-component-functions-directly

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.

宣言的UIについて調べると良さそう
https://zenn.dev/begineer/articles/8bc95caec85d86

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ありがと〜,以前にも言われた気がするわ.申し訳!
🩹 update: PRレビュー対応: DOMを操作しないように修正
ここで対応

Comment thread src/components/ui/Tag/index.stories.tsx Outdated
},
colorStyle: {
control: "select",
options: ["purple-blue", "red-pink", "green", "blue", "orange", "yellow"],
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.

ここはtype別に定義してるとこから持ってきたい

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Comment thread src/components/ui/Tag/index.test.tsx Outdated
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.

こっちのテストも同様

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

こちらもこのコンポーネントにロジックはないのでテストは不要です。

Comment thread src/components/ui/index.ts Outdated
@@ -0,0 +1,3 @@
export { Tag } from "./Tag";
export { IconButton } from "./IconButton";
export { default as AddOrigamiButton } from "./AddOrigamiButton";
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.

default as AddOrigamiButton これあってる?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Comment thread .storybook/main.ts
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.

この辺の変更必要かどうか確かめて欲しいです!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

storybookのバージョンが悪さしてそうでした.
🩹 update: PRレビュー対応: main.tsの変更をロールバック
ここで修正DONE

Copy link
Copy Markdown
Contributor

@yutteee yutteee left a comment

Choose a reason for hiding this comment

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

commented

Comment thread src/types/model.ts Outdated
imageUrl: string;
searchKeyword?: string[];
procedure: Procedure;
difficulty?: number;
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.

型の情報量を減らしたい
少数が入ってきた場合のテストがあったけど、そもそも少数が入らないように設計すべきと思いました。

Suggested change
difficulty?: number;
difficulty?: 1 | 2 | 3 | 4 | 5;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Comment thread src/types/model.ts
export type RotateAxis = [Point, Point] | [];

// タグの色スタイル定義
export type ColorStyle =
Copy link
Copy Markdown
Contributor

@yutteee yutteee Oct 19, 2025

Choose a reason for hiding this comment

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

なんのカラースタイルかわかる命名にしたい
(ローカル変数ならこれでもいいが、exportしてるので)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

タグ名とカラーはセットではなくて,ユーザーが好きに選べる,というのを想定していたんだけど,ゆってぃー的には違ったかな?
とりあえず色がわかりやすいようにColorStyleを変更した上で,今日のミーティングで確認しますm

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

命名が分かりにくいという指摘でした!

別ファイルからColorStyleをimportした場合を想定すると、
tagで使うためのstyleだとわからず、意図しない場所で使われそうと思いました

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.

結論から言えば、これらのテストは全て不要だと思います。
このコンポーネント自体、ロジックは持っていないからです。

propsが渡されて、それをそのままレンダリングしてるだけですよね。(altとかlinkとか特に)
どういう見た目になるかとか、それはstorybookで書いてるので重複したコードになってます。

Comment thread src/components/ui/Tag/index.test.tsx Outdated
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.

こちらもこのコンポーネントにロジックはないのでテストは不要です。

Comment on lines +25 to +36
{Array.from({ length: 5 }, (_, index) => {
const starNumber = index + 1;
const isFilled = starNumber <= difficulty;
return (
<FaStar
key={starNumber}
className={`${styles.star} ${
isFilled ? styles.filled : styles.empty
}`}
/>
);
})}
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.

よくなりましたが、jsxのなかにconstとかが入ってくるのは宣言的UIの原則には反しているかと思います。ここはロジックを持たず、UIの宣言のみになるべきです。

UIとロジックを分離して書くとすればこうなるかなと思います。

const stars = Array.from({ length: 5 }, (_, index) => {
    const starNumber = index + 1;
    const isFilled = starNumber <= difficulty;
    return {
      number: starNumber,
      isFilled,
    };
  });

...

return (
...
         {stars.map((star) => (
            <FaStar
              key={star.number}
              className={`${styles.star} ${
                star.isFilled ? styles.filled : styles.empty
              }`}
            />
          ))}
...
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🐛 fix: Star周りの修正

こちらで修正

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.

強いて言えば、星のテストの部分はあってもなくてもいいかなくらいの認識です。

@YutaK1026 YutaK1026 changed the title [OC-67] ✨ feat: 折り紙難易度表示機能とラベル表示機能の実装 [DON'T MERGE] [OC-67] ✨ feat: 折り紙難易度表示機能とラベル表示機能の実装 Oct 27, 2025
Copy link
Copy Markdown
Contributor

@yutteee yutteee left a comment

Choose a reason for hiding this comment

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

nits commentしましたが全体的にokだと思います!

Comment thread src/types/model.ts
export type RotateAxis = [Point, Point] | [];

// タグの色スタイル定義
export type ColorStyle =
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.

命名が分かりにくいという指摘でした!

別ファイルからColorStyleをimportした場合を想定すると、
tagで使うためのstyleだとわからず、意図しない場所で使われそうと思いました

Comment on lines +9 to +11
type OrigamiListItem = (
props: Omit<Model, "searchKeyWord" | "procedure" | "color">
) => JSX.Element;
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.

imo

omit知らなかったけどちょっと型安全性悪そう

Omit<T, Keys>のKeysにTには無いプロパティキーを指定しても、TypeScriptコンパイラーは指摘しません。たとえば、Keysにタイポがあっても検出できないので注意が必要です。

https://typescriptbook.jp/reference/type-reuse/utility-types/omit

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.

omitで不要なプロパティを除くのではなく、
pick使って必要なプロパティを明示的に指定した方が安全性は上がりそう

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.

個人的にはtypeベタ書きで良い気がする
UIがmodelを意識する必要があるか?と言われるとないので

Suggested change
type OrigamiListItem = (
props: Omit<Model, "searchKeyWord" | "procedure" | "color">
) => JSX.Element;
type OrigamiListItem = (
id: string;
name: string;
imageUrl: string;
difficulty: 0 | 1 | 2 | 3 | 4;
tags: string[];
) => JSX.Element;

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants