Skip to content
Merged

main #325

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
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pnpm e2e e2e/path/to/file.spec.ts # 特定E2Eファイル
- `lint`はwarningでも修正すること
- 次に`/review`を実行して、レビュー結果を要修正、不要で分けて提示してください。
- 上記完了後、SubAgentで`/simplify`を実行してリファクタを行うこと(Context消費したくない)
- SubAgentのモデルはOpus4.6にしてください

### フロントエンド(UIあり)

Expand Down
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.10/schema.json",
"$schema": "https://biomejs.dev/schemas/2.4.11/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
Expand Down
Binary file modified convex-seeds/seeds/db.zip
Binary file not shown.
88 changes: 1 addition & 87 deletions convex/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,91 +105,5 @@ export declare const internal: FilterApi<
>;

export declare const components: {
migrations: {
lib: {
cancel: FunctionReference<
"mutation",
"internal",
{ name: string },
{
batchSize?: number;
cursor?: string | null;
error?: string;
isDone: boolean;
latestEnd?: number;
latestStart: number;
name: string;
next?: Array<string>;
processed: number;
state: "inProgress" | "success" | "failed" | "canceled" | "unknown";
}
>;
cancelAll: FunctionReference<
"mutation",
"internal",
{ sinceTs?: number },
Array<{
batchSize?: number;
cursor?: string | null;
error?: string;
isDone: boolean;
latestEnd?: number;
latestStart: number;
name: string;
next?: Array<string>;
processed: number;
state: "inProgress" | "success" | "failed" | "canceled" | "unknown";
}>
>;
clearAll: FunctionReference<
"mutation",
"internal",
{ before?: number },
null
>;
getStatus: FunctionReference<
"query",
"internal",
{ limit?: number; names?: Array<string> },
Array<{
batchSize?: number;
cursor?: string | null;
error?: string;
isDone: boolean;
latestEnd?: number;
latestStart: number;
name: string;
next?: Array<string>;
processed: number;
state: "inProgress" | "success" | "failed" | "canceled" | "unknown";
}>
>;
migrate: FunctionReference<
"mutation",
"internal",
{
batchSize?: number;
cursor?: string | null;
dryRun: boolean;
fnHandle: string;
name: string;
next?: Array<{ fnHandle: string; name: string }>;
oneBatchOnly?: boolean;
reset?: boolean;
},
{
batchSize?: number;
cursor?: string | null;
error?: string;
isDone: boolean;
latestEnd?: number;
latestStart: number;
name: string;
next?: Array<string>;
processed: number;
state: "inProgress" | "success" | "failed" | "canceled" | "unknown";
}
>;
};
};
migrations: import("@convex-dev/migrations/_generated/component.js").ComponentApi<"migrations">;
};
168 changes: 168 additions & 0 deletions convex/testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,174 @@ export const seedPaginationTestData = internalMutation({
},
});

/**
* 探索的テスト用:最新shop/recruitmentにスタッフ15人と現実的な希望シフトを投入
*/
export const seedRealisticStaffRequests = internalMutation({
args: {},
handler: async (ctx) => {
const shop = await ctx.db.query("shops").order("desc").first();
if (!shop) throw new Error("No shop found");

const recruitment = await ctx.db
.query("recruitments")
.withIndex("by_shopId", (q) => q.eq("shopId", shop._id))
.order("desc")
.first();
if (!recruitment) throw new Error("No recruitment found");

const start = new Date(recruitment.periodStart);
const dates: string[] = [];
for (let i = 0; i < 7; i++) {
const d = new Date(start);
d.setDate(d.getDate() + i);
dates.push(d.toISOString().slice(0, 10));
}
const isWeekend = (i: number) => {
const dow = new Date(dates[i]).getDay();
return dow === 0 || dow === 6;
};

type Pattern = {
name: string;
email: string;
mode: "requests" | "allOff" | "unsubmitted";
pick: (i: number) => { startTime: string; endTime: string } | null;
};
const patterns: Pattern[] = [
{
name: "田中 健太",
email: "tanaka.kenta@example.com",
mode: "requests",
pick: (i) =>
isWeekend(i) ? { startTime: "17:00", endTime: "25:00" } : { startTime: "19:00", endTime: "23:00" },
},
{
name: "佐藤 美咲",
email: "sato.misaki@example.com",
mode: "requests",
pick: (i) => (i === 3 ? null : { startTime: "17:00", endTime: "24:00" }),
},
{
name: "鈴木 翔太",
email: "suzuki.shota@example.com",
mode: "requests",
pick: (i) => ([1, 3, 4].includes(i) ? { startTime: "18:00", endTime: "23:00" } : null),
},
{
name: "高橋 由美",
email: "takahashi.yumi@example.com",
mode: "requests",
pick: (i) => ([4, 5].includes(i) ? { startTime: "17:00", endTime: "22:00" } : null),
},
{
name: "伊藤 直樹",
email: "ito.naoki@example.com",
mode: "requests",
pick: (i) => (isWeekend(i) ? { startTime: "17:00", endTime: "21:00" } : null),
},
{
name: "渡辺 彩香",
email: "watanabe.ayaka@example.com",
mode: "requests",
pick: (i) => ([0, 2, 5].includes(i) ? { startTime: "18:30", endTime: "23:00" } : null),
},
{
name: "山本 隆",
email: "yamamoto.takashi@example.com",
mode: "requests",
pick: (i) => (i === 2 ? null : { startTime: "17:00", endTime: "25:00" }),
},
{
name: "中村 愛",
email: "nakamura.ai@example.com",
mode: "unsubmitted",
pick: () => null,
},
{
name: "小林 陽介",
email: "kobayashi.yosuke@example.com",
mode: "requests",
pick: (i) => (isWeekend(i) ? { startTime: "17:00", endTime: "24:00" } : null),
},
{
name: "加藤 真理",
email: "kato.mari@example.com",
mode: "requests",
pick: (i) => (!isWeekend(i) ? { startTime: "18:00", endTime: "22:00" } : null),
},
{
name: "吉田 亮",
email: "yoshida.ryo@example.com",
mode: "requests",
pick: (i) => (i === 6 ? null : { startTime: "17:00", endTime: "24:30" }),
},
{
name: "山田 美穂",
email: "yamada.miho@example.com",
mode: "requests",
pick: (i) => ([0, 2, 4].includes(i) ? { startTime: "18:00", endTime: "23:00" } : null),
},
{
name: "佐々木 翔",
email: "sasaki.sho@example.com",
mode: "requests",
pick: (i) => ([1, 4, 5, 6].includes(i) ? { startTime: "17:30", endTime: "22:30" } : null),
},
{
name: "松本 涼子",
email: "matsumoto.ryoko@example.com",
mode: "allOff",
pick: () => null,
},
{
name: "井上 大樹",
email: "inoue.daiki@example.com",
mode: "requests",
pick: (i) => ([2, 5].includes(i) ? { startTime: "19:00", endTime: "23:00" } : null),
},
];

let staffInserted = 0;
let requestsInserted = 0;
let submissionsInserted = 0;

for (const p of patterns) {
const staffId = await ctx.db.insert("staffs", {
shopId: shop._id,
name: p.name,
email: p.email,
isDeleted: false,
});
staffInserted++;

if (p.mode === "unsubmitted") continue;

for (let i = 0; i < 7; i++) {
const slot = p.pick(i);
if (!slot) continue;
await ctx.db.insert("shiftRequests", {
recruitmentId: recruitment._id,
staffId,
date: dates[i],
startTime: slot.startTime,
endTime: slot.endTime,
});
requestsInserted++;
}

await ctx.db.insert("shiftSubmissions", {
recruitmentId: recruitment._id,
staffId,
submittedAt: Date.now(),
});
submissionsInserted++;
}

return { staffInserted, requestsInserted, submissionsInserted, dates };
},
});

/**
* 探索的テスト用:シフト提出画面のテストデータを一括セットアップ
* shop + staff + recruitment + magicLink + session を作成し、sessionTokenを返す
Expand Down
8 changes: 4 additions & 4 deletions design/dashboard.pen
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@
"id": "15olP",
"name": "card1Submitted",
"fill": "$fg/muted",
"content": "提出状況: 8/10人",
"content": "提出済み: 8人",
"fontFamily": "Inter",
"fontSize": "$fontSize/sm",
"fontWeight": "normal"
Expand Down Expand Up @@ -629,7 +629,7 @@
"id": "6UZso",
"name": "card2Submitted",
"fill": "$fg/muted",
"content": "提出状況: 10/10人",
"content": "提出済み: 10人",
"fontFamily": "Inter",
"fontSize": "$fontSize/sm",
"fontWeight": "normal"
Expand Down Expand Up @@ -1691,7 +1691,7 @@
"id": "d3W9W",
"name": "spCard1Submitted",
"fill": "$fg/muted",
"content": "提出: 8/10人",
"content": "提出済み: 10人",
"fontFamily": "Inter",
"fontSize": "$fontSize/xs",
"fontWeight": "normal"
Expand Down Expand Up @@ -1818,7 +1818,7 @@
"id": "EeqAj",
"name": "spCard2Submitted",
"fill": "$fg/muted",
"content": "提出: 10/10人",
"content": "提出済み: 10人",
"fontFamily": "Inter",
"fontSize": "$fontSize/xs",
"fontWeight": "normal"
Expand Down
Binary file modified public/favicon.ico
Binary file not shown.
Binary file modified public/logo192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/logo512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ export const DashboardContent = ({
>
<Stack gap={1}>
<Text>全員分の希望がそろっていません</Text>
<Text>編集中にも変更される場合があります</Text>
<Text>編集中にも希望シフトが追加される場合があります</Text>
</Stack>
</Dialog>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { SaveDraftWarningContent } from "./index";

const meta = {
title: "Features/ShiftBoard/SaveDraftWarningContent",
component: SaveDraftWarningContent,
parameters: {
layout: "padded",
},
} satisfies Meta<typeof SaveDraftWarningContent>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Stack, Text } from "@chakra-ui/react";

export const SaveDraftWarningContent = () => {
return (
<Stack gap={3} fontSize="sm" lineHeight="tall">
<Text>一時保存後に提出されたシフトは、シフト予定(青いバー)が自動で設定されません。</Text>
<Text>以降提出されたシフトは手動でシフト予定時間を設定してください。</Text>
<Text>※スタッフの希望シフト(黒い点線)は、引き続き設定されます。</Text>
</Stack>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const AllVariants = () => (
periodLabel="1/20(月)〜1/26(日) のシフト"
confirmedAt={null}
onConfirm={() => {}}
onSaveDraft={() => {}}
viewMode="daily"
onViewModeChange={() => {}}
/>
Expand All @@ -33,6 +34,7 @@ const AllVariants = () => (
periodLabel="1/20(月)〜1/26(日) のシフト"
confirmedAt={new Date("2026-03-28T23:15:00")}
onConfirm={() => {}}
onSaveDraft={() => {}}
viewMode="overview"
onViewModeChange={() => {}}
/>
Expand All @@ -45,6 +47,7 @@ export const Variants: Story = {
periodLabel: "1/20(月)〜1/26(日) のシフト",
confirmedAt: null,
onConfirm: () => {},
onSaveDraft: () => {},
viewMode: "daily",
onViewModeChange: () => {},
},
Expand Down
5 changes: 5 additions & 0 deletions src/components/features/ShiftBoard/ShiftBoardHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const ShiftBoardHeader = ({
periodLabel,
confirmedAt,
onConfirm,
onSaveDraft,
viewMode,
onViewModeChange,
}: ShiftBoardHeaderProps) => {
Expand Down Expand Up @@ -37,6 +38,10 @@ export const ShiftBoardHeader = ({
<SegmentGroup.Items items={VIEW_OPTIONS} cursor="pointer" />
</SegmentGroup.Root>

<Button variant="outline" size="sm" onClick={onSaveDraft}>
一時保存
</Button>

{isConfirmed ? (
<Button variant="outline" size="sm" borderColor="teal.600" color="teal.600" onClick={onConfirm}>
再通知する
Expand Down
Loading
Loading