Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frontend
VITE_API_URL=
VITE_CLIENT_URL=
VITE_REDIRECT_URL=
VITE_IDENTEAPOT_SALT=
Comment on lines +3 to +5

Copilot AI Jan 17, 2026

Copy link

Choose a reason for hiding this comment

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

The VITE_CLIENT_URL entry appears on line 3 but was likely already present in the file. However, the ordering in .env.example is inconsistent with products/frontend/.env.example where VITE_CLIENT_URL comes before VITE_REDIRECT_URL. While this doesn't affect functionality, consistency across environment example files improves maintainability.

Copilot uses AI. Check for mistakes.

# backend
POSTGRES_USER=
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-frontend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
VITE_API_URL: ${{ secrets.VITE_API_URL }}
VITE_CLIENT_URL: ${{ secrets.VITE_CLIENT_URL }}
VITE_REDIRECT_URL: ${{ secrets.VITE_REDIRECT_URL }}
VITE_IDENTEAPOT_SALT: ${{ secrets.VITE_IDENTEAPOT_SALT }}
run: nix develop --command bash -c "pnpm i && pnpm run build"
# Deploy Frontend to Cloudflare Workers
- name: Deploy Frontend to Cloudflare Workers
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/preview-frontend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
VITE_API_URL: ${{ secrets.VITE_API_URL }}
VITE_CLIENT_URL: ${{ secrets.VITE_CLIENT_URL }}
VITE_REDIRECT_URL: ${{ secrets.VITE_REDIRECT_URL }}
VITE_IDENTEAPOT_SALT: ${{ secrets.VITE_IDENTEAPOT_SALT }}
run: nix develop --command bash -c "pnpm i && pnpm run frontend:build"
# Deploy Preview to Cloudflare Workers
# Ref: https://zenn.dev/lalalatotoro/articles/b8fa632b53d332
Expand Down
36 changes: 0 additions & 36 deletions AI.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,39 +93,3 @@ groupのメンバー
貸し借りの登録ボタン
{groupId}の履歴一覧
※各履歴には、削除ボタンを付ける (削除すると、削除したメンバーがその項目に表示されると共に、その項目の文字列に訂正線が引かれる。「削除されました」の文字も追加する)



- メモ

```ts
import { useEffect, type FC } from 'react';
// @tanstack/react-query
import { $api } from '../../api/fetchClient';
// react-router
import { useNavigate } from 'react-router';

const SessionCheck: FC = () => {
// sessionのチェック
const navigate = useNavigate();
const sessionCheckMutation = $api.useMutation('get', '/api/session', {
onError: () => {
navigate('/login', { replace: true });
},
});
useEffect(() => {
sessionCheckMutation.mutate({ credentials: 'include' });
}, []);

return (
<>
<h1>Pay Crew2</h1>
{sessionCheckMutation.isPending && <p>セッションの確認中...</p>}
{sessionCheckMutation.isError && <p>セッションが無効です。ログインページへリダイレクトします...。</p>}
{sessionCheckMutation.isSuccess && <p>各コンテンツ</p>;};
</>
);
}

export default SessionCheck;
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"@hookform/resolvers": "catalog:frontend",
"@scalar/hono-api-reference": "catalog:backend",
"@tanstack/react-query": "^5.90.5",
"@teapotlabs/identeapots": "catalog:frontend",
"@types/pg": "catalog:backend",
"@types/react": "catalog:frontend",
"@types/react-dom": "catalog:frontend",
Expand Down
14 changes: 14 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ catalogs:
'@hookform/error-message': ^2.0.1
'@hookform/resolvers': ^5.2.2
'@tanstack/react-query': ^5.90.5
"@teapotlabs/identeapots": ^1.1.1
'@types/react': ^19.2.2
'@types/react-dom': ^19.2.2
'@vitejs/plugin-react-swc': ^4.2.0
Expand Down
1 change: 1 addition & 0 deletions products/frontend/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
VITE_API_URL=
VITE_CLIENT_URL=
VITE_REDIRECT_URL=
VITE_IDENTEAPOT_SALT=
1 change: 1 addition & 0 deletions products/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"ui": "vitest run --ui --typecheck"
},
"dependencies": {
"@teapotlabs/identeapots": "catalog:frontend",
"@hookform/error-message": "catalog:frontend",
"@hookform/resolvers": "catalog:frontend",
"better-auth": "catalog:",
Expand Down
2 changes: 2 additions & 0 deletions products/frontend/src/api/openapi.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export interface paths {
"application/json": {
user_id: string;
user_name: string;
/** Format: uri */
user_avatar_url: string | null;
Comment on lines +33 to +34

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Align session response type with backend payload

The OpenAPI type now claims /api/session returns user_avatar_url, but the backend handler in products/backend/src/presentation/routes/check.ts still only returns user_id and user_name. Any frontend code that starts using user_avatar_url based on this type will see undefined at runtime (not string | null) and can mis-handle avatar rendering. Either add the field to the backend response/schema or remove it here to keep the contract accurate.

Useful? React with 👍 / 👎.

};
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.ul {
list-style: none;
margin: 0 auto;
width: fit-content;
max-width: 900px;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.ul {
list-style: none;
margin: 0 auto;
width: fit-content;
max-width: 900px;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,18 @@

.nav {
display: flex;
align-items: center;
gap: var(--space-base);
}

@media screen and (max-width: 499px) {
.nav {
.identicon {
width: 40px;
height: 40px;
border-radius: 50%;
}
Comment on lines +22 to +26

Copilot AI Jan 17, 2026

Copy link

Choose a reason for hiding this comment

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

The identicon will be hidden on mobile screens (max-width: 499px) because the entire nav is set to display: none at line 30. This may be intentional, but consider whether the avatar should remain visible on mobile even if other navigation links are hidden, as it's an important user identity indicator.

Copilot uses AI. Check for mistakes.

@media screen and (max-width: 599px) {
.navLink {
display: none;
}
}
30 changes: 27 additions & 3 deletions products/frontend/src/routes/Share/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import { useEffect, type FC } from 'react';
import { useEffect, useState, type FC } from 'react';
// @tanstack/react-query
import { $api } from '../../../../api/fetchClient';
// react-router
import { Link, NavLink, useNavigate } from 'react-router';
// icons
import { generateIdenteapot } from '@teapotlabs/identeapots';
// toast
import { toast } from 'react-hot-toast';
// css
import styles from './index.module.css';

const Header: FC = () => {
const [identicon, setIdenticon] = useState<string>('');
// sessionのチェック
const navigate = useNavigate();
const sessionCheckMutation = $api.useMutation('get', '/api/session', {
onSuccess: async (data) => {
try {
const salt = import.meta.env.VITE_IDENTEAPOT_SALT satisfies string;
const icon = await generateIdenteapot(data.user_id, salt);
setIdenticon(icon);
} catch {
toast.error('アイコンの生成に失敗しました。');
}
},
onError: () => {
navigate('/login', { replace: true });
},
});

useEffect(() => {
sessionCheckMutation.mutate({ credentials: 'include' });
}, []);

Copilot AI Jan 17, 2026

Copy link

Choose a reason for hiding this comment

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

The useEffect has an empty dependency array but uses sessionCheckMutation, which should be included in the dependencies or the mutation call should be wrapped in a ref or callback to avoid stale closure issues. Additionally, this will cause the session check to run on every component mount, which could be inefficient if the component remounts frequently.

Suggested change
}, []);
}, [sessionCheckMutation]);

Copilot uses AI. Check for mistakes.
Expand All @@ -24,8 +39,17 @@ const Header: FC = () => {
Pay Crew2
</Link>
<nav className={styles.nav}>
<NavLink to="/">トップ</NavLink>
<NavLink to="/gen-group">グループ作成</NavLink>
<NavLink className={styles.navLink} to="/">
トップ
</NavLink>
<NavLink className={styles.navLink} to="/gen-group">
グループ作成
</NavLink>
{sessionCheckMutation.isSuccess ? (
<>{identicon && <img className={styles.identicon} src={identicon} alt="User Identicon" />}</>
) : (
<NavLink to="/login"> ログイン</NavLink>
)}
</nav>
</header>
);
Expand Down
3 changes: 3 additions & 0 deletions setup/src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const dotenvLoader = (): EnvConfig => {
const viteApiUrl = caster.castString(process.env.VITE_API_URL);
const viteClientUrl = caster.castString(process.env.VITE_CLIENT_URL);
const viteRedirectUrl = caster.castString(process.env.VITE_REDIRECT_URL);
const viteIdenteapotSalt = caster.castString(process.env.VITE_IDENTEAPOT_SALT);
const postgresUser = caster.castString(process.env.POSTGRES_USER);
const postgresPassword = caster.castString(process.env.POSTGRES_PASSWORD);
const postgresDb = caster.castString(process.env.POSTGRES_DB);
Expand All @@ -33,6 +34,7 @@ export const dotenvLoader = (): EnvConfig => {
VITE_API_URL: viteApiUrl,
VITE_CLIENT_URL: viteClientUrl,
VITE_REDIRECT_URL: viteRedirectUrl,
VITE_IDENTEAPOT_SALT: viteIdenteapotSalt ? '*****' : '',
POSTGRES_USER: postgresUser,
POSTGRES_PASSWORD: postgresPassword ? '*****' : '',
POSTGRES_DB: postgresDb,
Expand All @@ -50,6 +52,7 @@ export const dotenvLoader = (): EnvConfig => {
viteApiUrl,
viteClientUrl,
viteRedirectUrl,
viteIdenteapotSalt,
};
const backendConfig: BackendConfig = {
postgresUser,
Expand Down
1 change: 1 addition & 0 deletions setup/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const main = () => {
const frontendDotenvData = `VITE_API_URL=${envConfig.frontendConfig.viteApiUrl}
VITE_CLIENT_URL=${envConfig.frontendConfig.viteClientUrl}
VITE_REDIRECT_URL=${envConfig.frontendConfig.viteRedirectUrl}
VITE_IDENTEAPOT_SALT=${envConfig.frontendConfig.viteIdenteapotSalt}
`;
fileWriter('./products/frontend/.env', frontendDotenvData);
}
Expand Down
1 change: 1 addition & 0 deletions setup/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type FrontendConfig = {
viteApiUrl: string;
viteClientUrl: string;
viteRedirectUrl: string;
viteIdenteapotSalt: string;
};

export type BackendConfig = {
Expand Down